Blog
Blog copied to clipboard
[MDN] Map
Map
-
Map物件是 key-value 配對, 而且記得原本插入 keys 的順序. key 或 value 可以使用任何值(包括物件和原生值).
說明
-
Map物件會以插入的順序 iterate 項目 -for...of每次回傳[key, value]的陣列.
Key 的相等性
- 相等性是根據
sameValueZero演算法. -
NaN跟其他NaN相等(雖然NaN !== NaN), 其他值都會以===運算子的語義決定是否相等. - 目前的 ECMAScript 規格中,
-0和+0是相等的.
物件 vs. Maps
- 物件與
Map相似 - 兩者都可以- 設定 keys 和 values
- 取回那些 values
- 刪除 keys
- 偵測 key 是否有儲存值
| Map | Object | |
|---|---|---|
| 意外出現的 keys | 預設不含任何 keys. 只會有明確放入的配對 | 本身有 prototype, 所以含預設的 keys, 如果不注意可能會有衝突 |
| key 類型 | 任何值(包括 functions, objects 或任何原生值) | 必須是 String 或 Symbol |
| key 順序 | 以插入的順序 iterate entries, keys 和 values. | 雖然現在都有排序, 但以前沒有, 而且順序很複雜. 所以, 最好不要依賴屬性順序 |
| 大小 | 數量可以從 size 屬性取得 |
手動取得數量 |
| Iteration | iterable, 所以可直接 iterate | 沒有實作 iteration protocol, 無法直接使用 JS for...of(可以用 Object.keys/Object.entries)(如果是物件的屬性是 enumerable 可以用 for...in) |
| 效能 | 適合頻繁地新增刪除配對會 |
不適合頻繁地新增刪除配對 |
設定物件屬性
// X
let wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
// 這樣做不會動到 Map 的資料結構. 他用的是一般物件的功能.
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
- 正確使用是透過
set(key, value)方法儲存資料
let contacts = new Map();
contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });
contacts.has("Jessie"); // true
contacts.get("Hilary"); // undefined
contacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });
contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete("Raymond"); // false
contacts.delete("Jessie"); // true
console.log(contacts.size); // 1
範例
使用
let myMap = new Map();
let keyString = "a string";
let keyObj = {};
let keyFunc = function () {};
// 設值
myMap.set(keyString, "是一個字串");
myMap.set(keyObj, "是一個 keyObj");
myMap.set(keyFunc, "是一個 keyFunc");
myMap.size; // 3
// 取值
myMap.get(keyString); // "是一個字串"
myMap.get(keyObj); // "是一個 keyObj"
myMap.get(keyFunc); // "是一個 keyFunc"
myMap.get("a string"); // "是一個字串"
// 因為 keyString === 'a string'
myMap.get({}); // undefined, 因為 keyObj !== {}
myMap.get(function () {}); // undefined, 因為 keyFunc !== function () {}
用 NaN 當作 Map keys
-
NaN也可以用作 key. 就算每個NaN都和本身不相等(NaN !== NaN), 以下的範例都會正常, 因為NaN彼此難以區分:
let myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN);
// "not a number"
let otherNaN = Number("foo");
myMap.get(otherNaN);
// "not a number"
用 for..of
let myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (let [key, value] of myMap) {
console.log(key + " = " + value);
}
// 0 = zero
// 1 = one
for (let key of myMap.keys()) {
console.log(key);
}
// 0
// 1
for (let value of myMap.values()) {
console.log(value);
}
// zero
// one
for (let [key, value] of myMap.entries()) {
console.log(key + " = " + value);
}
// 0 = zero
// 1 = one
用 forEach()
myMap.forEach(function (value, key) {
console.log(key + " = " + value);
});
// 0 = zero
// 1 = one
與陣列物件的關係
let kvArray = [
["key1", "value1"],
["key2", "value2"],
];
// 用正規的 Map constructor 轉換 2維 key-value 陣列
let myMap = new Map(kvArray);
myMap.get("key1"); // 回傳 "value1"
// 用 Array.from() 轉回 2D key-value 陣列
console.log(Array.from(myMap)); // 這個陣列會跟 kvArray 一樣
// 使用 spread 語法
console.log([...myMap]);
// 或使用 keys() / values() iterators, 轉成陣列
console.log(Array.from(myMap.keys())); // ["key1", "key2"]
複製與合併
- 複製 Map
let original = new Map([[1, "one"]]);
let clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false (淺層比較)
注意: 資料本身沒有複製
- Maps 可以合併, 但保持 key 的唯一性
let first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
let second = new Map([
[1, "uno"],
[2, "dos"],
]);
// 合併兩個 maps. 後者重複的 key 覆蓋前者.
// Spread 運算子本質上將 Map 轉成陣列
let merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
- Maps 也可以和陣列合併
let first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
let second = new Map([
[1, "uno"],
[2, "dos"],
]);
// 用陣列合併 maps. 後者重複的 key 覆蓋前者.
let merged = new Map([...first, ...second, [1, "eins"]]);
console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
瀏覽器相容
- IE 部分支援, 手持 Opera Android 不支援
@@toStringTag, 其他瀏覽器都支援