在JavaScript中编写枚举的最有效方法
我从Vue源代码中学到的一个技巧
[

](bytefish.medium.com/?source=pos…)
[
bytefish
](bytefish.medium.com/?source=pos…)
[
2小时前-4
](betterprogramming.pub/the-most-ef…
照片:Joe CaioneonUnsplash
JavaScript语言本身并不支持枚举。如果我们想模拟枚举,我们可以使用一个对象。
假设有这样一个场景,我们需要统计员工的技术栈,目前,我们需要标记的技术是CSS、JavaScript、HTML、WebGL。
那么我可以这样写枚举。
const SKILLS = { CSS: 1 , JS: 2, HTML: 3, WEB_GL: 4}
我之前是这样写的,但是最近我在阅读Vue源代码的时候,发现了一个高效使用枚举的技巧,在这里和大家分享一下。
定义枚举
我们可以这样来写上面的枚举。
const SKILLS = { CSS: 1 , JS: 1 << 1, HTML: 1 << 2, WEB_GL: 1 << 3}
什么是<< ?
左移运算符(**<<****)**将第一个操作数向左移动指定的位数。向左移出的多余的位被丢弃。零位则从右边移入。
比如说。
1在二进制中是0000 0001,把它向左移一位是0000 0010,在十进制中是2。- 如果我们把它移到两个位,它将变成
0000 0100,十进制是4。 - 如果我们把它移到3位,它将变成
0000 1000,即十进制的8。 - 如果我们把它移到N位,它将变成十进制的
2^N。
使用方法
按照上述方法定义了枚举后,我们可以这样使用。


提示:| 是位数OR运算符,它在每个位上返回一个1 ,其中任一或两个操作数的对应位是1s。
const a = 5; // 00000000000000000000000000000101const b = 3; // 00000000000000000000000000000011
如何理解这段代码?
在JavaScript中,整数被存储在4个字节中,也就是32位。第一个代表正数和负数,后面的31位代表数字。
当我们用二进制表示1 ,1 << 2 ,它们看起来像这样。


我们定义的枚举变量在二进制格式中只有一个1 ,而且它们所占的位置不同。
当我们为技能添加枚举选项时,我们使用skills | skill 。假设现在我们需要添加的技能是SKILLS.CSS ,那么在执行过程中,它就是。


我们可以发现,在skills ,对应于SKILLS.CSS 的位置将变成1。
相反,那么我们可以通过检查skills & SKILLS.CSS 的结果是否为0来判断SKILLS.CSS 是否存在于skills 中。
顺便说一下,在这里我们也可以发现这个技巧有一个缺点,那就是枚举项不能超过31。
为什么我们要使用这个技巧呢?
答案很简单,这样的代码运行起来更有性能。在CPU中有直接对应于位操作的指令,所以效率更高。
我们还可以做一个性能测试。
如果我们不使用位操作而使用传统方法(数组或地图)来实现,那么代码如下。
通过数组。
按地图。
下面是性能测试,由 [jsbench.me](https://jsbench.me/):


使用逐位枚举,性能会明显提高。
从Vue源代码中学习
我是从Vue的源代码中学习的。
export const enum ShapeFlags { ELEMENT = 1, FUNCTIONAL_COMPONENT = 1 << 1, STATEFUL_COMPONENT = 1 << 2, TEXT_CHILDREN = 1 << 3, ARRAY_CHILDREN = 1 << 4, SLOTS_CHILDREN = 1 << 5, TELEPORT = 1 << 6, SUSPENSE = 1 << 7, COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8, COMPONENT_KEPT_ALIVE = 1 << 9, COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT}
第一次读到这段代码时,我有点迷惑,但我终于想明白了。
希望这招对你有帮助。谢谢你的阅读。