Js WeakMap and WeakSet(弱映射和弱集合)

可達(dá)性

通常,當(dāng)對象、數(shù)組之類的數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中時,它們的子元素,如對象的屬性、數(shù)組的元素都被認(rèn)為是可達(dá)的。
如果使用對象作為常規(guī) Map 的鍵,那么當(dāng) Map 存在時,該對象也將存在。它會占用內(nèi)存,并且不會被(垃圾回收機(jī)制)回收。

例如:

let john = {name: "John”};

let map = new Map();
map.set(john, '...');

//john 被存儲在了 map 中,
//我們可以使用 map.keys() 來獲取它

WeakMap 在這方面有著根本的不同。它不會阻止垃圾回收機(jī)制作為對鍵的對象(key object)的回收。

WeakMap

WeakMapMap 的第一個不同點就是,WeakMap 的鍵必須是對象,不能是原始值:

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok");  //正常工作(以對象為鍵)

//不能使用字符串作為鍵
weakMap.set("test", "Whoops");  //Error,因為 “test” 不是一個對象

現(xiàn)在,如果我們在 weakMap 中使用一個對象作為鍵,并且沒有其他對這個對象的引用 —— 該對象將會被從內(nèi)存(和map)中自動清除。

let john = {name: "John"};

let weakMap = new WeakMap();
weakMap.set(john, "...");

john = null;  //覆蓋引用

//john 被從內(nèi)存中刪除了!

如果 john 僅僅是作為 WeakMap 的鍵而存在 —— 它將會從 map (和內(nèi)存中)自動刪除。

WeakMap 不支持迭代以及 keys(),values()entries() 方法。所以沒有辦法獲取 WeakMap 的所有鍵或值。

WeakMap 只有以下的方法:

  • `weakMap.get(key)
  • `weakMap.set(key, value)
  • `weakMap.delete(key)
  • `weakMap.has(key)

為什么會有這種限制呢?這是技術(shù)的原因。如果一個對象丟失了其它所有引用(就像上面示例中的 john),那么它就會被垃圾回收機(jī)制自動回收。但是在從技術(shù)的角度并不能準(zhǔn)確知道 何時會被回收。

這些都是由 JavaScript 引擎決定的。JavaScript 引擎可能會選擇立即執(zhí)行內(nèi)存清理,如果現(xiàn)在正在發(fā)生很多刪除操作,那么 JavaScript 引擎可能就會選擇等一等,稍后再進(jìn)行內(nèi)存清理。因此,從技術(shù)上講,WeakMap 的當(dāng)前元素的數(shù)量是未知的。JavaScript 引擎可能清理了其中的垃圾,可能沒清理,也可能清理了一部分。因此,暫不支持訪問 WeakMap 的所有鍵/值的方法。

那么,在哪里我們會需要這樣的數(shù)據(jù)結(jié)構(gòu)呢?

使用案例

WeakSet

WeakSet 的表現(xiàn)類似:

  • Set 類似,但是我們只能向 WeakSet 添加對象(而不是原始值)。
  • 對象只有在其它某個(些)地方被訪問的時候,才能留在 set 中。
  • Set 一樣, WeakSet 支持 add,hasdelete 方法,但不支持 sizekeys()`,并且不可迭代。

變“弱(weak)”的同時,它也可以作為額外的存儲空間。但并非針對任意數(shù)據(jù),而是針對“是/否”的事實。WeakSet 的元素可能代表著有關(guān)該對象的某些信息。

例如,我們可以將用戶添加到 WeakMap 中,以追蹤訪問過我們網(wǎng)站的用戶:

let visitedSet = new WeakSet();

let john = {name: "John"};
let pete = {name: "Pete"};
let mary = {name: "Mary"};

visitedSet.add(john);  //John 訪問了我們
visitedSet.add(pete);  //然后是 Pete
visitedSet.add(john);  //John 再次訪問

//visitedSet 現(xiàn)在有兩個用戶了

//檢查 John 是否來訪過?
alert(visitedSet.has(john));  //true

//檢查 Mary 是否來訪過?
alert(visitedSet.has(mary));  //false

john = null;

//visitedSet 將被自動清理(即自動清理其中已失效的值 john)

WeakMapWeakSet 最明顯的局限性就是不能迭代,并且無法獲取所有當(dāng)前內(nèi)容。那樣可能會造成不便,但是并不會阻止 WeakMap/WeakSet 完成其主要工作 —— 成為在其它地方管理/存儲“額外”的對象數(shù)據(jù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容