JavaScript 的 Map 指南

做者:Valeri Karpov

翻譯:瘋狂的技術宅javascript

原文:http://thecodebarbarian.com/t...html

未經容許嚴禁轉載前端

在JavaScript中,Map 是存儲鍵/值對的對象。Map 相似於通常 JavaScript 對象 ,但對象與 Map 之間一些關鍵的差別使 Map 頗有用。java

Map 與 Object

若是你要建立一個存儲一些鍵/值路徑的 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, agerank

這也可以保證符合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 ,由於它避免了原型污染的風險。


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索