何時使用 Map 來代替普通的 JS 對象
JS 普通對象 {key: 'value'} 用于存放結(jié)構(gòu)化數(shù)據(jù)。但有一件事我覺得很煩:對象鍵必須是字符串(或很少使用的 symbol)。
如果將數(shù)字用作鍵會怎樣?在這種情況下不會有錯誤:

JS 會隱式地將對象的鍵轉(zhuǎn)換為字符串,這種默認(rèn)行為丟失了類型的一致性,要解決也挺棘手的。但 ES6 中的Map 對象可以幫我們解決這類的問題,Look See See。
1. Map 接受任何類型的鍵
如前所述,如果對象的鍵不是 string 或 symbol,JS 將隱式地將其轉(zhuǎn)換為字符串。
幸運的是,map 的鍵類型沒有問題

1 和 2 是 numbersMap 中的鍵,這些鍵的類型(數(shù)字)保持不變。
可以在 mpa 中使用任何鍵類型:數(shù)字、布爾值、字符串和 symbol。

booleansMap 使用 booleans 作為鍵,沒有問題。相反,布爾鍵在普通對象中不起作用。
來突破一下想象:是否將整個對象作為 map 的鍵,答案:可以的。
1.1 對象作為鍵
假設(shè)你需要存儲一些與對象相關(guān)的數(shù)據(jù),而不需要將這些數(shù)據(jù)附加到對象本身。使用普通對象是不可能的。
解決方法是使用對象-值元組數(shù)組:

kindOfMap 是一個數(shù)組,包含對象和關(guān)聯(lián)值的對。
這種方法最大的問題是按鍵訪問值的復(fù)雜度O(n),咱們必須遍歷整個數(shù)組才能通過鍵獲得所需的值。

WeakMap (Map的一個專門版本)不需要這么麻煩就能做到上面的事情:它只接受對象作為鍵。
Map 和 Weakmap 之間的主要區(qū)別是,Weakmap 允許對鍵對象進(jìn)行垃圾收集,從而防止內(nèi)存泄漏。
好了,用 WeakMap 重構(gòu)上面的代碼就變得很簡單了:

與 Map 相反,WeakMap 只接受對象作為鍵,并少了一些方法。
2. map 對鍵名沒有限制
JS 中的任何對象都從原型對象繼承屬性,普通對象也是如此。
如果重寫從原型繼承的屬性,則可能會破壞依賴這些原型屬性的代碼:

在對象參與者上定義的屬性 toString 覆蓋從原型繼承的 toString() 方法。這中斷了isObject(),因為它依賴于 toString() 方法。
檢查普通對象從原型繼承的屬性和方法的列表, 避免使用這些方法名定義自定義屬性。
例如,假設(shè)有一個管理某些自定義字段的用戶界面。用戶可以通過指定名稱和值來添加自定義字段:

將定制字段的狀態(tài)存儲到普通對象中會很方便:

但是用戶可能會選擇一個自定義字段名稱,例如toString(如示例中所示),構(gòu)造函數(shù)等,這可能會破壞咱們的對象。
不要使用用戶輸入的值作為普通對象上鍵。
map 沒有這個問題,鍵值名稱不受限制:

不管 actorMap 有一個名為toString的屬性,toString()方法都可以正常工作。
3. map 是可迭代
為了遍歷普通對象的屬性,必須使用其他的輔助靜態(tài)函數(shù),如 Object.keys()或Object.entries():

Object.entries(colorsHex) 返回從對象提取的鍵值對數(shù)組。
但是,map 本身是可迭代的:

colorsHexMap是可迭代。可以在任何接受迭代的地方使用它:for()循環(huán),展開運算符[...map]。
map 提供了返回可迭代方法:map.keys() 遍歷鍵,map.values() 遍歷值
4. map 的大小
普通對象的另一個問題是,您無法立馬知道它包含的屬性的數(shù)量。

要確定 exams 的大小,必須通過所有鍵來確定它們的數(shù)量。
map 提供了 size 屬性,表示屬性的數(shù)量。

確定 map 的屬性的數(shù)量更加簡單:examsMap.size。
總結(jié)
普通 JS 對象通??梢院芎玫乇4娼Y(jié)構(gòu)化數(shù)據(jù),但它們也有一些局限性:
- 只能用字符串或 sybmol 作為鍵
- 自己的對象屬性可能會與從原型繼承的屬性鍵沖突(例如toString,constructor等)。
- 對象不能用作鍵
所有這些問題都可以通過 map 輕松解決。而且,它們提供了諸如迭代器和易于進(jìn)行大小查找之類的好處。
不要將 map 當(dāng)作普通對象的替代品,而應(yīng)視為是普通對象補充。