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