鍵控集合

本章介紹透過鍵索引的資料集合;MapSet 物件包含的元素可按插入順序迭代。

Map

Map 物件

一個 Map 物件是一個鍵值對映,它可以按插入順序迭代其元素。

以下程式碼展示了 Map 的一些基本操作。另請參閱 Map 參考頁面以獲取更多示例和完整的 API。你可以使用 for...of 迴圈為每次迭代返回一個 [key, value] 陣列。

js
const sayings = new Map();
sayings.set("dog", "woof");
sayings.set("cat", "meow");
sayings.set("elephant", "toot");
sayings.size; // 3
sayings.get("dog"); // woof
sayings.get("fox"); // undefined
sayings.has("bird"); // false
sayings.delete("dog");
sayings.has("dog"); // false

for (const [key, value] of sayings) {
  console.log(`${key} goes ${value}`);
}
// "cat goes meow"
// "elephant goes toot"

sayings.clear();
sayings.size; // 0

Object 和 Map 的比較

傳統上,物件一直用於將字串對映到值。物件允許你將鍵設定為值、檢索這些值、刪除鍵以及檢測某個鍵是否儲存了內容。然而,Map 物件有一些額外的優勢,使它們成為更好的對映。

  • Object 的鍵是字串符號,而 Map 的鍵可以是任何值。
  • 你可以輕鬆獲取 Mapsize,而對於 Object,你必須手動跟蹤大小。
  • Map 的迭代是按照元素的插入順序進行的。
  • 一個 Object 有一個原型,所以對映中存在預設鍵。(這可以透過使用 map = Object.create(null) 來繞過。)

這三個提示可以幫助你決定使用 Map 還是 Object

  • 當鍵在執行時未知時,以及當所有鍵的型別相同且所有值的型別相同時,使用 Map 而不是物件。
  • 如果需要將原始值作為鍵儲存,請使用 map,因為物件將每個鍵都視為字串,無論是數字值、布林值還是任何其他原始值。
  • 當存在對單個元素進行操作的邏輯時,使用物件。

WeakMap 物件

一個 WeakMap 是一個鍵值對的集合,其鍵必須是物件或未註冊的符號,值可以是任何任意的JavaScript 型別,並且它不會對其鍵建立強引用。也就是說,物件作為 WeakMap 中的鍵存在並不會阻止該物件被垃圾回收。一旦用作鍵的物件被回收,它在任何 WeakMap 中對應的所有值也會成為垃圾回收的候選者——只要它們沒有被其他地方強引用。唯一可以作為 WeakMap 鍵的原始型別是符號——更具體地說,是未註冊的符號——因為未註冊的符號保證是唯一的,並且不能被重新建立。

WeakMap 的 API 與 Map 的 API 基本相同。然而,WeakMap 不允許觀察其鍵的活躍性,這就是它不允許列舉的原因。因此,沒有方法可以獲取 WeakMap 中鍵的列表。如果存在,該列表將取決於垃圾回收的狀態,從而引入不確定性。

有關更多資訊和示例程式碼,另請參閱 WeakMap 參考頁面上的“為什麼選擇 WeakMap?”。

WeakMap 物件的一個用例是儲存物件的私有資料,或隱藏實現細節。在以下示例中,私有資料和方法屬於物件內部,並存儲在 privates 物件中,該物件是一個 WeakMap。例項和原型上公開的一切都是公共的;其他一切都無法從外部訪問,因為 privates 未從模組匯出。

js
const privates = new WeakMap();

export default function Public() {
  const me = {
    // Private data goes here
  };
  privates.set(this, me);
}

Public.prototype.method = function () {
  const me = privates.get(this);
  // Do stuff with private data in `me`
  // …
};

注意: 此用例現在可以透過類和私有欄位實現。

Set

Set 物件

Set 物件是唯一值的集合。你可以按插入順序迭代其元素。Set 中的一個值只能出現一次;它在 Set 集合中是唯一的。

以下程式碼展示了 Set 的一些基本操作。另請參閱 Set 參考頁面以獲取更多示例和完整的 API。

js
const mySet = new Set();
mySet.add(1);
mySet.add("some text");
mySet.add("foo");

mySet.has(1); // true
mySet.delete("foo");
mySet.size; // 2

for (const item of mySet) {
  console.log(item);
}
// 1
// "some text"

Array 和 Set 之間的轉換

你可以使用 Array.from展開語法從 Set 建立一個 Array。此外,Set 建構函式接受一個 Array 進行反向轉換。

注意: Set 物件儲存唯一值——因此在轉換時,Array 中的任何重複元素都會被刪除!

js
Array.from(mySet);
[...mySet2];

mySet2 = new Set([1, 2, 3, 4]);

Array 和 Set 的比較

傳統上,在許多情況下,元素集合在 JavaScript 中儲存在陣列中。然而,Set 物件有一些優勢

  • 按值刪除 Array 元素 (arr.splice(arr.indexOf(val), 1)) 非常慢。
  • Set 物件允許你按值刪除元素。對於陣列,你必須根據元素的索引進行 splice 操作。
  • 在陣列中無法使用 indexOf 找到值 NaN
  • Set 物件儲存唯一值。你無需手動跟蹤重複項。

WeakSet 物件

WeakSet 物件是可垃圾回收值的集合,包括物件和未註冊的符號WeakSet 中的一個值只能出現一次。它在 WeakSet 集合中是唯一的。

Set 物件的主要區別在於

  • Set 不同,WeakSet 僅是物件或符號的集合,而不是任何型別的任意值的集合。
  • WeakSet 是*弱引用*的:對集合中物件的引用是弱持有的。如果對儲存在 WeakSet 中的物件沒有其他引用,它們就可以被垃圾回收。這也意味著集合中沒有儲存當前物件的列表。
  • WeakSet 不可列舉。

WeakSet 物件的用例是有限的。它們不會造成記憶體洩漏,因此安全地使用 DOM 元素作為鍵並標記它們以進行跟蹤等目的會很有用。

Map 和 Set 的鍵值相等性

Map 物件的鍵相等性和 Set 物件的值相等性均基於 SameValueZero 演算法

  • 相等性類似於全等比較運算子 ===
  • -0+0 被認為是相等的。
  • NaN 被認為與自身相等(與 === 相反)。