• 用 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

  • 相关阅读:
    iceberg-flink 七:累积窗口使用。(CUMULATE)
    如何创建一个React组件并渲染到DOM中?
    Svg Flow Editor 原生svg流程图编辑器(一)
    5. Makefile项目管理
    UML反刍
    微信小程序实现上拉加载更多
    C++11标准模板(STL)- 算法(std::merge)
    Excel 文件比较工具 xlCompare 11.01 Crack
    Apache服务Rwrite功能使用
    c++中的四种cast转换, dynamic_cast、static_cast、const_cast、reinterpret_cast
  • 原文地址:https://blog.csdn.net/JavaMonsterr/article/details/125447679