位枚举
位枚举是个啥
枚举
首先来说一下枚举,在一些语言中我们可以用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
中用位枚举还比较少,只用过一次,不过我感觉这种方式能解决不少判断的问题
而且二进制,多少带点快,干净又卫生