在JavaScript中编写枚举的最有效方法

788 阅读3分钟

在JavaScript中编写枚举的最有效方法

我从Vue源代码中学到的一个技巧

[

bytefish

](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位代表数字。

当我们用二进制表示11 << 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}

github1s.com/vuejs/core/…

第一次读到这段代码时,我有点迷惑,但我终于想明白了。

希望这招对你有帮助。谢谢你的阅读。