一文搞懂 ES6 的 Map,Map 和 Object 如何選擇
什麼是 Map
Map 是 ECMAScript 6 的新增特性,是一種新的集合類型,爲 javascript 帶來了真正的鍵 / 值存儲機 制。
-
Map 對象存有鍵值對,其中的鍵可以是任何數據類型。
-
Map 對象記得鍵的原始插入順序。
-
Map 對象具有表示映射大小的屬性。
Map 的基本 API
1、new Map() 創建新的 Map 對象
使用 new 關鍵字和 Map 構造函數可以創建一個空映射:
// 創建新的 Map 對象。
const m = new Map();
如果想在創建的同時初始化實例,可以給 Map 構造函數傳入一個可迭代對象,需要包含鍵 / 值對數 組。可迭代對象中的每個鍵 / 值對都會按照迭代順序插入到新映射實例中:
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m1.size) // 3
console.log(m1)
console 打印出的 m1 如下:
使用自定義迭代器初始化映射
// 使用自定義迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function*() {
yield ["key1", "val1"];
yield ["key2", "val2"];
yield ["key3", "val3"];
}
});
alert(m2.size); // 3
console.log(m2)
console 打印出的 m2 如下:
set()、 get()、has()、delete()、clear()
初始化之後,可以使用 set() 方法再添加鍵 / 值對。另外,可以使用 get() 和 has() 進行查詢,可 以通過 size 屬性獲取映射中的鍵 / 值對的數量,還可以使用 delete() 和 clear() 刪除值。
-
set() 方法再添加鍵 / 值對
-
get() 獲取 Map 對象中鍵的值
-
has() 進行查詢
-
delete() 刪除一個鍵 / 值對
-
clear() 清除這個映射實例中的所有鍵 / 值對
const m = new Map();
alert(m.has("firstName")); // false
alert(m.get("firstName")); // undefined
alert(m.size); // 0
m.set("firstName", "Matt")
.set("lastName", "Frisbie");
alert(m.has("firstName")); // true
alert(m.get("firstName")); // Matt
alert(m.size); // 2
m.delete("firstName"); // 只刪除這一個鍵/值對
alert(m.has("firstName")); // false
alert(m.has("lastName")); // true
alert(m.size); // 1
m.clear(); // 清除這個映射實例中的所有鍵/值對
alert(m.has("firstName")); // false
alert(m.has("lastName")); // false
alert(m.size); // 0
set() 方法返回映射實例,因此可以把多個操作連綴起來,包括初始化聲明:
const m = new Map().set("key1", "val1");
m.set("key2", "val2")
.set("key3", "val3");
alert(m.size); // 3
與 Object 只能使用數值、字符串或符號作爲鍵不同,Map 可以使用任何 JavaScript 數據類型作爲 鍵。
const m = new Map();
const functionKey = function() {};
const symbolKey = Symbol();
const objectKey = new Object();
m.set(functionKey, "functionValue");
m.set(symbolKey, "symbolValue");
m.set(objectKey, "objectValue");
alert(m.get(functionKey)); // functionValue
alert(m.get(symbolKey)); // symbolValue
alert(m.get(objectKey)); // objectValue
Map 的順序與迭代
與 Object 類型的一個主要差異是,Map 實例會維護鍵值對的插入順序,因此可以根據插入順序執 行迭代操作。Map 映射實例可以提供一個迭代器(Iterator),能以插入順序生成 [key, value] 形式的數組。
entries() 返回 Map 對象中鍵 / 值對的數組。
Map 映射實例提供一個迭代器(Iterator),能以插入順序生成 [key, value] 形式的數組。可以 通過 entries()方法(或者 Symbol.iterator 屬性,它引用 entries())取得這個迭代器:
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
因爲 entries() 是默認迭代器,所以可以直接對映射實例使用擴展操作,把映射轉換爲數組:
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]]
如果不使用迭代器,而是使用回調方式,則可以調用映射的 forEach(callback, opt_thisArg) 方法並傳入回調,依次迭代每個鍵 / 值對。
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
m.forEach((val, key) => alert(`${key} -> ${val}`));
// key1 -> val1
// key2 -> val2
// key3 -> val3
keys() 和 values() 分別返回以插入順序生成鍵和值
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
for (let key of m.keys()) {
alert(key);
}
// key1
// key2
// key3
for (let key of m.values()) {
alert(key);
}
// value1
// value2
// value3
選擇 object 還是 map
Map 的大多數特性都可以通過 Object 類型實現,但二者之間還是存在一些細微的差異。對於大部分業務開發者來說,選擇 object 還是 map 只是個人喜好問題,其實影響不大。但是對於追求業務和性能的開發者來說,object 和 map 確實存在很大的區別。在具體實踐中使用哪一個,還是值得細細甄別。
1. 內存佔用
同一瀏覽器中給定固定大小的內存,Map 大約可以比 Object 多存儲 50% 的鍵 / 值對。
2. 插入性能
向 Object 和 Map 中插入新鍵 / 值對的消耗大致相同,不過插入 Map 在所有瀏覽器中一般會稍微快 一點兒。對這兩個類型來說,插入速度並不會隨着鍵 / 值對數量而線性增加。如果代碼涉及大量插入操 作,那麼顯然 Map 的性能更佳。
3. 查找速度
與插入不同,從大型 Object 和 Map 中查找鍵 / 值對的性能差異極小,但如果只包含少量鍵 / 值對, 則 Object 有時候速度更快。如果代碼涉及大量查找操作,那麼某些情況下可能選 擇 Object 更好一些。
4、刪除性能
對大多數瀏覽器引擎來說,Map 的 delete() 操作都比插入和查找更快。如果代碼涉及大量刪除操作,那麼毫無疑問應該選擇 Map。
文章參考自《JavaScript 高級程序設計第四版》
微信號:javascriptyishu
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/n-lxVoHpqNzaswjKbrlrFg