做者:Valeri Karpov翻譯:瘋狂的技術宅javascript
原文:http://thecodebarbarian.com/t...html
未經容許嚴禁轉載前端
在JavaScript中,Map 是存儲鍵/值對的對象。Map 相似於通常 JavaScript 對象 ,但對象與 Map 之間一些關鍵的差別使 Map 頗有用。java
若是你要建立一個存儲一些鍵/值路徑的 JavaScript 對象,能夠定義一個普通 JavaScript 對象(plain-old JavaScript object),其簡稱爲「 POJO」,以下所示。jquery
const obj = { name: 'Jean-Luc Picard', age: 59, rank: 'Captain' }; obj.name; // 'Jean-Luc Picard'
你還能夠定義一個包含以下所示的鍵和值的映射。程序員
const map = new Map([ // 你能夠經過二維數組定義 Map。 首先 // 每一個嵌套數組的元素是鍵,第二個是值 ['name', 'Jean-Luc Picard'], ['age', 59], ['rank', 'Captain'] ]); // 要得到與 Map 中給定的「鍵」關聯的值,你須要 // 調用 map.get(key)`。 使用 map.key 將不起做用。 map.get('name'); // 'Jean-Luc Picard'
假設你想得到 Picard 船長的 age
。對於一個對象,你能夠用 obj.age
。對於 map,你要用 map.get('age')
。對於與內置 JavaScript 功能沒有衝突的屬性來講這很好用,可是若是你想獲取對象的 constructor
屬性會怎樣呢?在這種狀況下,只定義了 obj.constructor
,但未定義 map.get('constructor')
。面試
obj.constructor; // [Function: Object] map.get('constructor'); // undefined
映射沒有繼承的任何概念:映射沒有任何繼承的鍵。這使 map 成爲存儲原始數據的理想選擇,而沒必要擔憂數據與現有方法和屬性發生衝突。例如,map 不受原型污染這個安全漏洞的影響,用戶數據的簡單複製可能會使惡意用戶覆蓋類方法。segmentfault
另外一個關鍵差別是,映射容許你存儲對象鍵,而不只僅是字符串。可是當你把日期或數字等對象存儲爲鍵時,可能會引發一些混亂。數組
const map = new Map([]); const n1 = new Number(5); const n2 = new Number(5); map.set(n1, 'One'); map.set(n2, 'Two'); // n1 和 n2 是對象,所以 n1!== n2。 // 這意味着 map 具備分別用於 n1 和 n2 的鍵。 map.get(n1); // 'One' map.get(n2); // 'Two' map.get(5); // undefined //若是要對一個對象執行此操做,則 n2 會覆蓋 n1 const obj = {}; obj[n1] = 'One'; obj[n2] = 'Two'; obj[n1]; // 'Two' obj[5]; // 'Two'
Map 還具備 size
屬性,該屬性返回 map 中鍵/值對的數量。爲了得到一個對象中鍵的數量,你必需要調用 Object.keys(obj).length
。瀏覽器
map.size; // 3
另外一個區別是,這保證了鍵在 map 中的順序。換句話說,若是你調用 map.keys()
,你將老是按照將鍵添加到 map 的順序獲取鍵。在 Picard 船長的示例中,map.keys()
將始終按該順序返回 name
, age
和 rank
。
這也可以保證符合ES6的瀏覽器的對象鍵順序。例如在與 ES6 兼容的 JavaScript 運行時中,Object.keys(obj)
將始終返回 ['name', 'age', 'rank']
。可是在較早的運行時(例如 Internet Explorer 等)中,Object.keys(obj)
可能會以不一樣的順序返回鍵。
Map#keys()
, Map#values()
, Map#entries()
map 具備3種內置的迭代方法:keys()
,values()
)和entries()
。與Object.keys()
不一樣,Map#keys()
函數返回一個 iterator 而不是數組。這意味着迭代 map 鍵的最簡單方法是使用 for/of
循環。
const map = new Map([ ['name', 'Jean-Luc Picard'], ['age', 59], ['rank', 'Captain'] ]); const iterator = map.keys(); console.log(iterator); // MapIterator { 'name', 'age', 'rank' } // `map.keys()` returns an iterator, not an array, so you can't // access the values using `[]` iterator[0]; // undefined // The `for/of` loop can loop through iterators for (const key of map.keys()) { key; // 'name', 'age', 'rank' }
有時將迭代器轉換爲數組很方便,所以你能夠用 filter()
和 map()
。將迭代器轉換成數組的最簡單方法是使用內置的 Array.from()
函數。
const arr = Array.from(map.keys()); arr.length; // 3 arr[0]; // 'name' arr[1]; // 'age' arr[2]; // 'rank'
Map#entries()
函數還返回一個迭代器。迭代器遍歷 map 的值:
for (const v of map.values()) { v; // 'Jean-Luc Picard', 59, 'Captain' }
最後, Map#entries()
返回一個迭代器,該迭代器以與 Map 構造函數相似的格式遍歷 map 的鍵/值對。 Map#entries()
函數是 Map 類的等效項,它等效於 `Object.entries
。
for (const [key, value] of map.entries()) { key; // 'name', 'age', 'rank' value; // 'Jean-Luc Picard', 59, 'Captain' }
Map#entries()
函數使複製 map 變得很容易。克隆 map 就像將 Map.entries()
轉換成數組同樣簡單:
// `clone` is now a separate map that contains the same keys/values // as `map`. const clone = new Map(Array.from(map.entries));
儘管 JavaScript 開發人員一般用對象來存儲數據,可是 map 具備一些優勢:沒有原型污染或 JSON 數據覆蓋類方法的風險。若是要在不設置 symbol 的狀況下將數據與對象相關聯,映射還容許你存儲對象鍵,這會頗有用。Map 在開源 JavaScript 中仍然不多見,我惟一見過的重要用例子是 Mongoose's map type 。可是 map 值得去取代 JSON ,由於它避免了原型污染的風險。