試一試
const map = new Map();
map.set("a", 1);
map.set("b", 2);
map.set("c", 3);
console.log(map.get("a"));
// Expected output: 1
map.set("a", 97);
console.log(map.get("a"));
// Expected output: 97
console.log(map.size);
// Expected output: 3
map.delete("b");
console.log(map.size);
// Expected output: 2
描述
Map 物件是鍵值對的集合。Map 中的鍵只能出現一次;它在 Map 集合中是唯一的。Map 物件按鍵值對進行迭代 — 一個 for...of 迴圈在每次迭代中返回一個包含 [key, value] 的兩元素陣列。迭代按插入順序進行,這對應於每個鍵值對首次透過 set() 方法插入到 Map 中的順序(也就是說,當呼叫 set() 時,Map 中還沒有具有相同值的鍵)。
規範要求 Map 的實現“平均訪問時間應低於集合中元素數量的次線性”。因此,它可以在內部表示為雜湊表(O(1) 查詢)、搜尋樹(O(log(N)) 查詢)或任何其他資料結構,只要其複雜度優於 O(N)。
鍵的相等性
值的相等性基於 SameValueZero 演算法。(它曾經使用 SameValue,該演算法將 0 和 -0 視為不同。請檢視瀏覽器相容性。)這意味著 NaN 被認為是與 NaN 相同的(即使 NaN !== NaN 為 true),所有其他值都根據 === 運算子的語義被視為相等。此外,對於物件鍵,相等性基於物件標識。它們透過引用而非值進行比較。有關示例,請參閱使用 Map 物件。
Object 與 Map
Object 類似於 Map——兩者都允許你將鍵設定為值、檢索這些值、刪除鍵以及檢測某個鍵是否儲存了內容。因此(並且因為沒有內建替代方案),Object 歷史上一直被用作 Map。
然而,在某些情況下,Map 具有重要的差異,使其更優越:
| Map | Object | |
|---|---|---|
| 意外的鍵 | 預設情況下,Map 不包含任何鍵。它只包含顯式放入其中的內容。 |
注意:這可以透過使用 |
| 安全 | Map 可以安全地與使用者提供的鍵和值一起使用。 |
在 |
| 鍵型別 | Map 的鍵可以是任何值(包括函式、物件或任何原始值)。 |
Object 的鍵必須是 String 或 Symbol。 |
| 鍵的順序 |
|
儘管普通 順序最初僅在 ECMAScript 2015 中為自有屬性定義;ECMAScript 2020 也為繼承屬性定義了順序。但請注意,沒有單一機制可以迭代物件的所有屬性;各種機制都包含不同的屬性子集。( |
大小 |
Map 中的專案數量可以輕鬆地透過其 size 屬性檢索。 |
確定 Object 中的專案數量則更為間接且效率低下。一種常見的方法是透過 Object.keys() 返回的陣列的 length 屬性。 |
| 迭代 | Map 是一個可迭代物件,因此可以直接迭代。 |
備註
|
| 效能 |
在涉及頻繁新增和刪除鍵值對的場景中表現更好。 |
未針對頻繁新增和刪除鍵值對進行最佳化。 |
| 序列化和解析 |
沒有原生支援序列化或解析。 (但你可以透過使用帶有 replacer 引數的 |
使用 使用 |
設定物件屬性
設定物件屬性也適用於 Map 物件,並且可能導致相當大的混淆。
因此,這看起來是可行的:
const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
但是,這種設定屬性的方式不會與 Map 資料結構互動。它使用的是通用物件的特性。’bla’ 的值不會儲存在 Map 中進行查詢。對資料的其他操作將失敗。
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
將資料儲存在 Map 中的正確用法是透過 set(key, value) 方法。
const 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
類似 Map 的瀏覽器 API
瀏覽器中類似 Map 的物件(或“類 Map 物件”)是 Web API 介面,它們在許多方面行為類似於 Map。
就像 Map 一樣,條目可以按照它們新增到物件的相同順序進行迭代。類似 Map 的物件和 Map 也具有相同名稱和行為的屬性和方法。但是,與 Map 不同的是,它們只允許為每個條目的鍵和值使用特定的預定義型別。
允許的型別在規範 IDL 定義中設定。例如,RTCStatsReport 是一個類似 Map 的物件,它必須使用字串作為鍵,物件作為值。這在下面的規範 IDL 中定義:
interface RTCStatsReport {
readonly maplike<DOMString, object>;
};
類 Map 物件是隻讀或讀寫(參見上面 IDL 中的 readonly 關鍵字)。
- 只讀的類
Map物件具有size屬性,以及以下方法:entries()、forEach()、get()、has()、keys()、values()和Symbol.iterator()。 - 可寫的類
Map物件還具有以下方法:clear()、delete()和set()。
這些方法和屬性與 Map 中對應的實體具有相同的行為,除了鍵和值型別的限制。
以下是隻讀的類 Map 瀏覽器物件的示例:
建構函式
Map()-
建立一個新的
Map物件。
靜態屬性
Map[Symbol.species]-
用於建立派生物件的建構函式。
靜態方法
Map.groupBy()-
使用提供的回撥函式返回的值對給定可迭代物件的元素進行分組。最終返回的
Map使用測試函式中的唯一值作為鍵,這些鍵可用於獲取每個組中的元素陣列。
例項屬性
這些屬性在 Map.prototype 上定義,並由所有 Map 例項共享。
Map.prototype.constructor-
建立例項物件的建構函式。對於
Map例項,初始值是Map建構函式。 Map.prototype.size-
返回
Map物件中的鍵/值對的數量。 Map.prototype[Symbol.toStringTag]-
[Symbol.toStringTag]屬性的初始值是字串"Map"。此屬性用於Object.prototype.toString()。
例項方法
Map.prototype.clear()-
從
Map物件中移除所有鍵值對。 Map.prototype.delete()-
從此
Map中移除由鍵指定的條目。 Map.prototype.entries()-
返回一個新的迭代器物件,其中包含
Map物件中每個元素的[key, value]兩元素陣列,按插入順序排列。 Map.prototype.forEach()-
對
Map物件中存在的每個鍵值對呼叫callbackFn一次,按插入順序。如果向forEach提供了thisArg引數,它將用作每次回撥的this值。 Map.prototype.get()-
返回此
Map中與鍵對應的值,如果沒有則返回undefined。 Map.prototype.getOrInsert()實驗性-
返回此
Map中與指定鍵對應的值。如果鍵不存在,它將插入一個新條目,其中包含鍵和給定的預設值,並返回插入的值。 Map.prototype.getOrInsertComputed()實驗性-
返回此
Map中與指定鍵對應的值。如果鍵不存在,它將插入一個新條目,其中包含鍵和從給定回撥計算的預設值,並返回插入的值。 Map.prototype.has()-
返回一個布林值,指示此
Map中是否存在具有指定鍵的條目。 Map.prototype.keys()-
返回一個新的迭代器物件,其中包含
Map物件中每個元素的鍵,按插入順序排列。 Map.prototype.set()-
向此
Map新增一個具有指定鍵和值的新條目,如果鍵已存在,則更新現有條目。 Map.prototype.values()-
返回一個新的迭代器物件,其中包含
Map物件中每個元素的值,按插入順序排列。 Map.prototype[Symbol.iterator]()-
返回一個新的迭代器物件,其中包含
Map物件中每個元素的[key, value]兩元素陣列,按插入順序排列。
示例
使用 Map 物件
const myMap = new Map();
const keyString = "a string";
const keyObj = {};
const keyFunc = () => {};
// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
console.log(myMap.size); // 3
// getting the values
console.log(myMap.get(keyString)); // "value associated with 'a string'"
console.log(myMap.get(keyObj)); // "value associated with keyObj"
console.log(myMap.get(keyFunc)); // "value associated with keyFunc"
console.log(myMap.get("a string")); // "value associated with 'a string'", because keyString === 'a string'
console.log(myMap.get({})); // undefined, because keyObj !== {}
console.log(myMap.get(() => {})); // undefined, because keyFunc !== () => {}
將 NaN 用作 Map 鍵
NaN 也可以用作鍵。儘管每個 NaN 都不等於它自己(NaN !== NaN 為 true),但以下示例仍然有效,因為 NaNs 彼此之間無法區分:
const myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN);
// "not a number"
const otherNaN = Number("foo");
myMap.get(otherNaN);
// "not a number"
使用 for...of 迭代 Map
可以使用 for...of 迴圈迭代 Map:
const myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (const [key, value] of myMap) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
for (const key of myMap.keys()) {
console.log(key);
}
// 0
// 1
for (const value of myMap.values()) {
console.log(value);
}
// zero
// one
for (const [key, value] of myMap.entries()) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
使用 forEach() 迭代 Map
可以使用 forEach() 方法迭代 Map:
myMap.forEach((value, key) => {
console.log(`${key} = ${value}`);
});
// 0 = zero
// 1 = one
與 Array 物件的關聯
const kvArray = [
["key1", "value1"],
["key2", "value2"],
];
// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray);
console.log(myMap.get("key1")); // "value1"
// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray
// A succinct way to do the same, using the spread syntax
console.log([...myMap]);
// Or use the keys() or values() iterators, and convert them to an array
console.log(Array.from(myMap.keys())); // ["key1", "key2"]
克隆和合並 Map
就像 Array 一樣,Map 也可以被克隆:
const original = new Map([[1, "one"]]);
const clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false (useful for shallow comparison)
注意:請記住,資料本身不會被克隆。換句話說,這只是 Map 的淺複製。
Map 可以合併,同時保持鍵的唯一性:
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// Merge two maps. The last repeated key wins.
// Spread syntax essentially converts a Map to an Array
const merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
Map 也可以與數組合並:
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// Merge maps with an array. The last repeated key wins.
const merged = new Map([...first, ...second, [1, "un"]]);
console.log(merged.get(1)); // un
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-map-objects |
瀏覽器相容性
載入中…