社区编辑申请
注册/登录
用 JavaScript 编写枚举的最有效方法
开发 前端
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。
  • 如果我们将其移动三位,它将变为 0000 1000 ,即十进制的 8。
  • 如果我们将其移动 N 位,它将变为 2^Nin 十进制。

用法

按照上面的方法定义好枚举后,我们可以这样使用:

const SKILLS = {
CSS: 1 ,
JS: 1 << 1,
HTML: 1 << 2,
WEB_GL: 1 << 3
}
// Use this value to store a user's tech-stack
let skills = 0
// add a skill for the user
function addSkill(skill) {
skills = skills | skill
}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
// If this value is not 0, it means that the user has mastered the tech
console.log('Does he know CSS', SKILLS.CSS & skills)
console.log('Does he know JavaScript', SKILLS.JS & skills)
console.log('Does he know Web GL', SKILLS.WEB_GL & skills)

温馨提示:| 是按位或运算符,它在每个操作数的对应位为 1 的每个位位置返回 1。

cons
t a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a | b); // 00000000000000000000000000000111
// expected output: 7

如何理解这段代码?

在 JavaScript 中,整数存储在 4 个字节中,即 32 位。第一个代表正负,后面的31代表数字。

当我们用二进制表示 1 , 1 << 2 时,它们看起来像这样:

我们定义的枚举变量只有一个二进制格式的1,并且占据不同的位置。

当我们向技能添加枚举选项时,我们使用skills | skill。假设现在我们需要添加的技能是SKILLS.CSS,那么在执行过程中,就是:

我们可以发现,在技能中,SKILLS.CSS对应的位置会变成1。

反之,那么我们可以通过查看skills&SKILLS.CSS的结果是否为0来判断技能中是否存在SKILLS.CSS。

顺便说一句,这里我们也可以发现这个技巧有个缺点,就是枚举项不能超过 31 个。

我们为什么要使用这个技巧?

答案很简单,这样的代码运行起来更高效。CPU中有直接对应位操作的指令,因此效率更高。

我们也可以做一个性能测试。

如果我们不使用按位运算,而是使用传统的方法(数组或映射)来实现,那么代码如下。

Array 方法:

const SKILLS = {
CSS: 1 ,
JS: 1 << 1,
HTML: 1 << 2,
WEB_GL: 1 << 3
}
// Use an array to store the user's tech-stack
let skills = []
function addSkill(skill) {
if (!skills.includes(skill)) { // Avoid duplicate storage
skills.push(skill)
}
}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
skills.includes(SKILLS.CSS)
skills.includes(SKILLS.JS)
skills.includes(SKILLS.WEB_GL)

Map 方法:

const SKILLS = {
CSS: 1 ,
JS: 1 << 1,
HTML: 1 << 2,
WEB_GL: 1 << 3
}
// Use a map to store the user's tech-stack
let skills = {}
function addSkill(skill) {
if (!skills[skill]) {
skills[skill] = true
}
}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
skills[SKILLS.CSS]
skills[SKILLS.JS]
skills[SKILLS.WEB_GL]

这是 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
}

地址:https://github1s.com/vuejs/core/blob/HEAD/packages/shared/src/shapeFlags.ts

责任编辑:庞桂玉 来源: WEB前端开发社区
相关推荐

2022-06-21 09:26:21

Shell脚本JavaScript

2022-06-17 09:08:27

代码Python内置库

2022-06-21 12:27:12

JavaScript前端

2009-04-09 15:40:01

2022-06-07 09:30:35

2022-06-25 21:22:30

编程Rust代码

2022-06-27 10:26:37

枚举Java

2021-06-09 10:45:12

JavaScript开发 编程

2022-04-07 16:03:36

JavaScriptTypeScript

2022-05-27 10:00:06

C++游戏引擎

2018-12-03 17:15:47

2022-05-03 22:25:57

Python浏览器语言

2022-05-10 10:28:21

2022-03-24 09:44:54

TypeScriptSOLID

2010-03-02 14:12:30

WCF枚举类型

2022-06-09 09:20:40

Linux语言编写代码

2022-03-31 11:17:58

JavaScript数组方法

2022-02-25 09:19:32

TypeScript辅助函数枚举

2022-06-08 09:11:55

测试代码开发

2012-05-10 15:21:50

JavaScript

同话题下的热门内容

源码探秘:Python 中对象是如何被调用的?使用Java和Python进行数据统计和分析C++与Java“相爱相杀”:一个步步紧逼,一个节节败退GitHub这五个骚操作,99%的人不知道!裁员真能拯救中国互联网?吐血推荐17个提升开发效率的“轮子”哪个版本的JVM最快?Flask vs Django: 该如何选择Python框架?

编辑推荐

2017年9月编程语言排行榜:Java、C与C++三巨头还能统治排行榜多久?2017年最受欢迎的5个前端框架比较2017年11月编程语言排行榜:脚本语言怎么了?2017年3月编程语言排行榜:Swift首次进入前十最近租房有点烦!技术人如何用Python找到称心如意的“小窝”?
我收藏的内容
点赞
收藏

51CTO技术栈公众号