亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

ES6+ WeakSet

1. 前言

上一節我們學習了 Set 數據結構,本節將學習與它類似的數據結構 WeakSet,不同的是 WeakSet 存放的數據是一個弱引用類型。在 JavaScript 中,對象的引用是強保留的,這意味著只要持有對象的引用,它就不會被垃圾回收。JavaScript 屬于高級語言, 存在 GC 機制,不需要直接地去操作內存,避免了很多問題。同時也讓一些內存泄漏的問題變得更加不易察覺,所以 ES6 引入了 WeakSet 和 WeakMap 這樣存儲弱引用類型的數據結構,是不會阻止它被垃圾回收的。

2. 基本用法

WeakSet 對象允許你將一個弱引用對象報錯在一個集合中。和 Set 一樣,它們都是構造函數,都需要實例化才能使用。WeakSet 可以接收一個可迭代對象作為參數,則該對象的所有迭代值都會被自動添加進生成的 WeakSet 對象中。null 被認為是 undefined。

const ws = new WeakSet([iterable]);

WeakSet 對數據的操作方法相對 Set 是比較少的,只有添加、刪除和查找,而且不能被遍歷。

方法名 描述
add 向 WeakSet 實例中添加值
delete 刪除 WeakSet 實例中的指定值
has 查找指定的值是否在 WeakSet 實例中

WeakSet 存放的一般都是對象的引用,如下實例:

var ws = new WeakSet();
var obj1 = {};
var obj2 = {};

ws.add(obj1);
ws.add(obj2);

ws.has(obj1);    // true
ws.has(obj2);   // true

ws.delete(obj1); // 從 set 中刪除 obj1 對象
ws.has(obj1);    // false, obj1 對象已經被刪除了
ws.has(obj2);    // true, obj2 依然存在

3. 對比 Set

WeakSet 對象是一些對象值的集合,并且其中的每個對象值都只能出現一次。在 WeakSet 的集合中是唯一的,這和 Set 對象是一樣的。

WeakSetSet 還是有明顯的區別的,主要區別有兩點:

  • Set 相比,WeakSet 只能是對象的集合,而不能是任何類型的任意值,這個 Set 可以存儲任何類型的值不同;
  • WeakSet 是弱引用:WeakSet 對象中存儲的對象值都是被弱引用的,如果沒有其他的變量或屬性引用這個對象值,則這個對象值會被當成垃圾回收掉。正因為這樣,WeakSet 對象是無法被枚舉的,沒有辦法拿到它包含的所有元素。

當我們去取一個對象進行操作時,外界必然存在對這個對象的引用,否則我們不可能取到這個對象。而弱引用到底是做什么的呢?

首先我們要知道對象的生命周期是,只有對象存在引用就不會被 GC 回收。但有時候我們只是需要這個集合去判斷一些邏輯,如果使用 Set 對象的話,就會存在引用,這樣實例化的內容就不會被回收。這時,使用 WeakMap 就是有必要的事了。讓我們來看下面的這個實例:

const requests = new WeakSet();
class ApiRequest {
  constructor() {
    requests.add(this);
  }

  makeRequest() {
    if(!request.has(this)) throw new Error("Invalid access");
    // do work
  }
}

上面的代碼中,ApiRequest 想驗證一下 this 的來源,使用 WeakMap 來存儲這個 this 對象,并在 makeRequest 執行時去驗證一下是否是 ApiRequest 這個類。這里的 requests 實例并不想參與到 ApiRequest 類中的生命周期中去,它只是作為一個條件判斷使用的。如果使用 Set 對象的話,這個實例就會在 ApiRequest 類中存在引用關系,并一直保存在實例中,增加內存的開銷,也可能會發生內存泄漏。而使用 WeakMap 則不同它是弱引用,只有在劫持的時候才會被獲取到。

4. 小結

本節學習了 WeakMap 對象,它用了存儲對象的值,存儲的值都是弱引用類型。其實,弱引用就是將對象鍵添加到 WeakSet 上,而 WeakSet 對對象的引用不會影響垃圾回收,也就是說,你持有對象的引用,就可以獲取元數據。一旦不再持有對象的引用,即使你仍持有并添加了該對象的引用,也會被垃圾回收。