首頁 >web前端 >js教程 >ES6集合:使用地圖,設置,弱圖,弱點

ES6集合:使用地圖,設置,弱圖,弱點

Joseph Gordon-Levitt
Joseph Gordon-Levitt原創
2025-02-15 12:37:11812瀏覽

ES6 Collections: Using Map, Set, WeakMap, WeakSet

本文探討了四個新的ES6集合以及它們帶來的好處。

大多數主要的編程語言都有幾種類型的數據集合。 Python有列表、元組和字典。 Java有列表、集合、映射、隊列。 Ruby有哈希和數組。到目前為止,JavaScript只有數組。對象和數組是JavaScript的得力助手。 ES6引入了四個新的數據結構,它們將增強語言的強大功能和表達能力:Map、Set、WeakSet和WeakMap。

關鍵要點

  • ES6引入了四個新的數據結構:Map、Set、WeakSet和WeakMap。這些集合允許更具表達性和功能強大的JavaScript編程。
  • ES6中的Map和Set是任何類型的鍵值對的集合。它們針對快速檢索進行了優化,並提供添加、刪除和循環遍歷值的方法。但是,它們對對象持有強引用,如果對像很大且不再需要,則可能代價很高。
  • ES6還引入了WeakMap和WeakSet,它們類似於Map和Set,但對對象持有弱引用。這意味著當這些對像不再需要時,可以對其進行垃圾回收,這對於內存管理非常有益。
  • 雖然新的ES6集合提供了更大的靈活性,但在許多情況下,JavaScript對象仍然可以用作集合。在決定是否使用對像或鍵控集合時,開發人員應考慮諸如需要動態鍵查找、值的互換性和添加或刪除鍵值對的頻率等因素。

尋找JavaScript HashMap

HashMap、字典和哈希是各種編程語言存儲鍵值對的幾種方法,這些數據結構針對快速檢索進行了優化。

在ES5中,JavaScript對象(只是具有鍵和值的屬性的任意集合)可以模擬哈希,但是使用對像作為哈希有幾個缺點。

缺點#1:ES5中的鍵必須是字符串

JavaScript對象屬性鍵必須是字符串,這限制了它們作為不同數據類型鍵值對集合的能力。當然,您可以將其他數據類型強制轉換為字符串,但這會增加額外的工作。

缺點#2:對象並非天生可迭代

對象並非設計為集合,因此沒有有效的方法來確定對像有多少屬性。 (例如,Object.keys速度很慢)。當您循環遍歷對象的屬性時,您還會獲得其原型屬性。您可以向所有對象添加可迭代屬性,但並非所有對像都旨在用作集合。您可以使用for … in循環和hasOwnProperty()方法,但這只是一個變通方法。當您循環遍歷對象的屬性時,屬性不一定會按照插入的順序檢索。

缺點#3:內置方法衝突的挑戰

對象具有內置方法,如constructor、toString和valueOf。如果將其中一個添加為屬性,則可能導致衝突。您可以使用Object.create(null)創建一個裸對象(不繼承自object.prototype),但這仍然只是一個變通方法。

ES6包含新的集合數據類型,因此不再需要使用對象並忍受它們的缺點。

使用ES6 Map集合

Map是我們將要檢查的第一個數據結構/集合。 Map是任何類型的鍵值對的集合。創建新的Map、添加/刪除值、循環遍歷鍵/值以及有效地確定其大小很容易。以下是關鍵方法:

創建映射並使用常用方法

<code class="language-javascript">const map = new Map(); // 创建一个新的Map
map.set('hobby', 'cycling'); // 设置键值对

const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // 新对象
const normalfoods = {}; // 新对象

map.set(normalfoods, foods); // 设置两个对象作为键值对

for (const [key, value] of map) {
  console.log(`${key} = ${value}`); // hobby = cycling  [object Object] = [object Object]
}

map.forEach((value, key) => {
  console.log(`${key} = ${value}`);
}, map); // hobby = cycling  [object Object] = [object Object]

map.clear(); // 清除键值对
console.log(map.size === 0); // True
</code>

在JSBin上運行此示例

使用Set集合

Set是有序的值列表,不包含重複項。 Set不是像數組那樣被索引,而是使用鍵訪問。 Set已經存在於Java、Ruby、Python和許多其他語言中。 ES6 Set與其他語言中的Set之間的一個區別是,順序在ES6中很重要(在許多其他語言中並非如此)。以下是關鍵的Set方法:

<code class="language-javascript">const planetsOrderFromSun = new Set();
planetsOrderFromSun.add('Mercury');
planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // 可链式方法
console.log(planetsOrderFromSun.has('Earth')); // True

planetsOrderFromSun.delete('Mars');
console.log(planetsOrderFromSun.has('Mars')); // False

for (const x of planetsOrderFromSun) {
  console.log(x); // 输入和输出顺序相同 - Mercury Venus Earth
}
console.log(planetsOrderFromSun.size); // 3

planetsOrderFromSun.add('Venus'); // 尝试添加重复项
console.log(planetsOrderFromSun.size); // 仍然是3,没有添加重复项

planetsOrderFromSun.clear();
console.log(planetsOrderFromSun.size); // 0
</code>

在JSBin上運行此示例

弱集合、內存和垃圾回收

JavaScript垃圾回收是一種內存管理形式,其中不再引用的對象會自動刪除,並且其資源會被回收。

Map和Set對對象的引用是強持有的,並且不允許垃圾回收。如果map/set引用不再需要的大的對象(例如已經從DOM中刪除的DOM元素),這可能會變得很昂貴。

為了解決這個問題,ES6還引入了兩個新的弱集合,稱為WeakMap和WeakSet。這些ES6集合是“弱”的,因為它們允許不再需要的對像從內存中清除。

WeakMap

WeakMap是我們介紹的第三個新的ES6集合。 WeakMap類似於普通的Map,但方法較少,並且在垃圾回收方面存在上述差異。

<code class="language-javascript">const aboutAuthor = new WeakMap(); // 创建新的WeakMap
const currentAge = {}; // 键必须是对象
const currentCity = {}; // 键必须是对象

aboutAuthor.set(currentAge, 30); // 设置键值
aboutAuthor.set(currentCity, 'Denver'); // 键值可以是不同数据类型

console.log(aboutAuthor.has(currentCity)); // 测试WeakMap是否包含键

aboutAuthor.delete(currentAge); // 删除键
</code>

使用案例

WeakMap有幾個流行的用例。它們可以用來保持對象的私有數據私有,也可以用來跟踪DOM節點/對象。

私有數據用例

以下示例來自JavaScript專家Nicholas C. Zakas:

<code class="language-javascript">var Person = (function() {
  var privateData = new WeakMap();

  function Person(name) {
    privateData.set(this, { name: name });
  }

  Person.prototype.getName = function() {
    return privateData.get(this).name;
  };

  return Person;
}());
</code>

在這裡使用WeakMap簡化了保持對像數據私有的過程。可以引用Person對象,但是如果沒有特定的Person實例,則不允許訪問privateDataWeakMap。

DOM節點用例

Google Polymer項目在一個名為PositionWalker的代碼片段中使用WeakMap。

PositionWalker跟踪DOM子樹中的位置,作為當前節點和該節點內的偏移量。

WeakMap用於跟踪DOM節點的編輯、刪除和更改:

<code class="language-javascript">const map = new Map(); // 创建一个新的Map
map.set('hobby', 'cycling'); // 设置键值对

const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // 新对象
const normalfoods = {}; // 新对象

map.set(normalfoods, foods); // 设置两个对象作为键值对

for (const [key, value] of map) {
  console.log(`${key} = ${value}`); // hobby = cycling  [object Object] = [object Object]
}

map.forEach((value, key) => {
  console.log(`${key} = ${value}`);
}, map); // hobby = cycling  [object Object] = [object Object]

map.clear(); // 清除键值对
console.log(map.size === 0); // True
</code>

WeakSet

WeakSet是其元素在不再需要它們引用的對象時可以進行垃圾回收的Set集合。 WeakSet不允許迭代。它們的用例相當有限(至少目前是這樣)。大多數早期採用者說WeakSet可以用來標記對象而無需修改它們。 ES6-Features.org有一個從WeakSet添加和刪除元素的示例,以便跟踪對像是否已被標記:

<code class="language-javascript">const planetsOrderFromSun = new Set();
planetsOrderFromSun.add('Mercury');
planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // 可链式方法
console.log(planetsOrderFromSun.has('Earth')); // True

planetsOrderFromSun.delete('Mars');
console.log(planetsOrderFromSun.has('Mars')); // False

for (const x of planetsOrderFromSun) {
  console.log(x); // 输入和输出顺序相同 - Mercury Venus Earth
}
console.log(planetsOrderFromSun.size); // 3

planetsOrderFromSun.add('Venus'); // 尝试添加重复项
console.log(planetsOrderFromSun.size); // 仍然是3,没有添加重复项

planetsOrderFromSun.clear();
console.log(planetsOrderFromSun.size); // 0
</code>

Map所有事物?記錄與ES6集合

Map和Set是鍵值對的漂亮的新ES6集合。也就是說,JavaScript對象仍然可以在許多情況下用作集合。除非情況需要,否則無需切換到新的ES6集合。

MDN有一個很好的問題列表,用於確定何時使用對像或鍵控集合:

  • 鍵通常直到運行時才知道嗎?您需要動態查找它們嗎?
  • 所有值都具有相同的類型,並且可以互換使用嗎?
  • 您是否需要不是字符串的鍵?
  • 經常添加或刪除鍵值對嗎?
  • 您是否有任意數量(易於更改)的鍵值對?
  • 集合是否被迭代?

新的ES6集合產生更易用的JavaScript

JavaScript集合以前非常有限,但這已通過ES6得到糾正。這些新的ES6集合將增強語言的強大功能和靈活性,並簡化採用它們的JavaScript開發人員的任務。


本文是來自Microsoft技術佈道者和DevelopIntelligence關於實用JavaScript學習、開源項目和互操作性最佳實踐(包括Microsoft Edge瀏覽器和新的EdgeHTML渲染引擎)的Web開發系列的一部分。 DevelopIntelligence通過appendTo(其專注於前端的博客和課程網站)提供JavaScript培訓和React培訓課程。

我們鼓勵您在包括Microsoft Edge(Windows 10的默認瀏覽器)在內的各種瀏覽器和設備上進行測試,可以使用dev.microsoftedge.com上的免費工具,包括EdgeHTML問題跟踪器,您可以在其中報告或搜索EdgeHTML問題,例如網站渲染或標準合規性問題。此外,請訪問Edge博客,以獲取來自Microsoft開發人員和專家的最新信息。

關於ES6集合的常見問題解答 (FAQ):Map、Set、WeakMap、WeakSet

JavaScript ES6中Map和WeakMap的主要區別是什麼?

在JavaScript ES6中,Map和WeakMap都用於存儲鍵值對。但是,它們之間存在一些顯著差異。首先,在Map中,鍵可以是任何類型,而在WeakMap中,鍵必須是對象。其次,Map具有size屬性,允許您檢查鍵值對的數量,但WeakMap沒有此屬性。最後,Map對鍵對象持有強引用,這意味著只要Map存在,它們就沒有資格進行垃圾回收。另一方面,WeakMap對鍵對象持有弱引用,這意味著如果對對像沒有其他引用,則可以對其進行垃圾回收。

如何在JavaScript ES6中迭代WeakMap或WeakSet?

與Map和Set不同,WeakMap和WeakSet沒有迭代其元素的方法。這是因為它們旨在對它們的鍵(WeakMap)或值(WeakSet)持有弱引用,這意味著這些可以在任何時間進行垃圾回收。因此,無法保證在嘗試迭代元素時元素仍然存在。如果您需要迭代集合,則應改用Map或Set。

我可以在WeakMap或WeakSet中使用原始數據類型作為鍵嗎?

不可以,您不能在WeakMap或WeakSet中使用原始數據類型作為鍵。這些集合中的鍵必須是對象。這是因為WeakMap和WeakSet對它們的鍵持有弱引用,這意味著如果對它們沒有其他引用,則可以對鍵進行垃圾回收。原始數據類型(例如數字和字符串)不會像對像那樣進行垃圾回收,因此它們不能用作這些集合中的鍵。

為什麼我應該使用WeakMap或WeakSet而不是Map或Set?

WeakMap和WeakSet具有一些獨特的特性,在某些情況下,它們可能比Map或Set更合適。因為它們對它們的鍵(WeakMap)或值(WeakSet)持有弱引用,所以當它們不再使用時,可以對其進行垃圾回收。如果您想將其他數據與對象關聯,但又不想阻止對像在不再需要時進行垃圾回收,這將非常有用。此外,因為WeakMap和WeakSet沒有迭代其元素的方法,所以它們可以為它們存儲的數據提供一定程度的隱私。

當WeakMap或WeakSet中的鍵被垃圾回收時會發生什麼?

當WeakMap或WeakSet中的鍵被垃圾回收時,集合中的相應條目會自動刪除。這是因為這些集合對它們的鍵持有弱引用,這意味著當它們不再使用時,可以對鍵進行垃圾回收。此功能對於管理JavaScript應用程序中的內存非常有用,因為它確保與不再使用的對象關聯的數據也會被清除。

我可以使用WeakMap或WeakSet來存儲臨時數據嗎?

是的,WeakMap和WeakSet非常適合存儲臨時數據。因為它們對它們的鍵(WeakMap)或值(WeakSet)持有弱引用,所以當它們不再使用時,可以對其進行垃圾回收。這意味著當鍵被垃圾回收時,存儲在這些集合中的數據也會被清除。這對於存儲僅在短時間內需要的有用,因為您不必擔心手動清理它。

如何檢查WeakMap或WeakSet是否包含某個鍵或值?

您可以使用has方法來檢查WeakMap或WeakSet是否包含某個鍵。此方法返回一個布爾值,指示該鍵是否存在於集合中。但是,請記住,您不能使用此方法來檢查WeakSet中的某個值,因為此集合中的值是不可訪問的。

我可以從WeakMap或WeakSet中刪除條目嗎?

是的,您可以使用delete方法從WeakMap中刪除條目。此方法刪除與給定鍵關聯的條目,並返回一個布爾值,指示該鍵是否存在於集合中。但是,您不能從WeakSet中刪除條目,因為此集合沒有delete方法。

我可以清除WeakMap或WeakSet中的所有條目嗎?

不可以,您不能清除WeakMap或WeakSet中的所有條目。這些集合沒有clear方法,該方法在Map和Set中可用。這是因為WeakMap和WeakSet旨在在鍵被垃圾回收時自動清理它們的條目。

我可以獲取WeakMap或WeakSet的大小嗎?

不可以,您無法獲取WeakMap或WeakSet的大小。這些集合沒有size屬性,該屬性在Map和Set中可用。這是因為由於垃圾回收,WeakMap或WeakSet的大小可以隨時更改。

以上是ES6集合:使用地圖,設置,弱圖,弱點的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn