位枚举
位枚举是个啥
枚举
首先来说一下枚举,在一些语言中我们可以用enum等关键字定义枚举,它的作用是让值更易读
比如我们设置一个人的状态:吃饭、睡觉、打豆豆,分别为0、1、2
如果我们在一个地方判断这个人当前状态是否是吃饭会用status == 0
但时间长了你可能就忘了0是指的什么,所以你还要需要去看
枚举就可以解决这个问题,以C#为例
1  | enum STATUS  | 
使用时status == STATUS.EAT,我们就明确知道是在判断状态等于吃饭
在JS中也可以实现,就是自己定义变量的方式
1  | const STATUS = Object.freeze({  | 
其中freeze可以让这个对象不会被更改
位
位就是可以进行位运算(我的理解),比如C#可以用Flags将枚举标记为位域
1  | []  | 
此时你可以这样判断status.HasFlag(STATUS.EAT)
但当判断项只有一个可能看不出它的优势,别急我们先用JS演示一下
JS模仿C#位枚举
定义
定义方式与C#一毛一样
1  | const STATUS = Object.freeze({  | 
也可以直接设置为数字的 1、2、4,左移只是更易读
封装一个 HasFlag
1  | function hasFlag(enums, flags) {  | 
它的原理就是让枚举和枚举变量与(&)枚举对比
至于这种封装方式,我也不知道对不对,应该有更好的方法
发生了什么
假设我们有一个状态
1  | const status = STATUS.EAT  | 
使用hasFlag
1  | hasFlag(status, STATUS.EAT)  | 
等号左边的二进制是0000 0001
等号右边的二进制进行了与运算
1  | 0000 0001  | 
最终结果是两边都是0000 0001,所以等式成立返回true
更令人舒适的
单看上面的方式,你完全可以用status === STATUS.EAT
但位枚举可以同时表述一种以上的状态,比如边吃饭边打豆豆
只需要加个或
1  | const status = STATUS.EAT | STATUS.HIT_DOUDOU  | 
再使用hasFlag验证一下
1  | hasFlag(status, STATUS.EAT)  | 
以上均为true
状态的切换
位枚举切换状态非常简单,假设我正在边吃饭边打豆豆
1  | let status = STATUS.EAT | STATUS.HIT_DOUDOU  | 
现在我要移除吃饭状态,添加睡觉状态,我只需要一个异或
1  | status ^= STATUS.EAT | STATUS.SLEEP  | 
异或就是相同为0,不同为1,所以就去掉了吃饭,添加了睡觉
1  | 0000 0101  | 
(在梦里打豆豆)
除了某种状态
不存在某种状态时返回true,但写法得倒过来,条件状态在前
1  | hasFlag(~STATUS.EAT, status) // 除了吃饭  | 
告辞
目前我在javascript中用位枚举还比较少,只用过一次,不过我感觉这种方式能解决不少判断的问题
而且二进制,多少带点快,干净又卫生
