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 }
到此這篇關於JavaScript 編寫枚舉的最有效方法分享的文章就介紹到這瞭,更多相關JavaScript 枚舉編寫內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- JS循環中正確使用async、await的姿勢分享
- JavaScript數組常用方法解析及數組扁平化
- JavaScript數組詳細歸納
- Javascript Object對象類型使用詳解
- javascript數組includes、reduce的基本使用