WeakMap
)(進階)弱映射類似於映射,但有以下差異
接下來的兩個章節將更詳細地探討這意味著什麼。
無法檢查弱映射內部有什麼
這些限制啟用了安全性屬性。引用Mark Miller
弱映射/鍵對應值的對應只能由同時擁有弱映射和鍵的人觀察或影響。使用 `clear()`,只擁有弱映射的人就可以影響弱映射和鍵到值的對應。
弱映射的鍵被稱為弱持有的:通常,如果一個物件參照另一個物件,則後者物件在第一個物件存在時無法被垃圾回收。使用弱映射時,情況不同:如果一個物件是鍵且沒有在其他地方被參照,則它可以在弱映射仍然存在時被垃圾回收。這也會導致對應的項目被移除(但沒有辦法觀察到)。
所有 WeakMap 鍵都必須是物件。如果您使用基本值,將會收到錯誤訊息
> const wm = new WeakMap();
> wm.set(123, 'test')TypeError: Invalid value used as weak map key
如果使用基本值作為鍵,WeakMap 將不再是黑盒子。但由於基本值永遠不會被垃圾回收,因此您無法從弱鍵中獲利,而且也可以使用一般 Map。
這是 WeakMap 的主要使用案例:您可以使用它們將值附加至物件,例如
const wm = new WeakMap();
{const obj = {};
.set(obj, 'attachedValue'); // (A)
wm
}// (B)
在第 A 行,我們將值附加至 obj
。在第 B 行,obj
已經可以被垃圾回收,即使 wm
仍然存在。將值附加至物件的這個技巧,等同於將物件的屬性儲存在外部。如果 wm
是屬性,之前的程式碼將如下所示
{const obj = {};
.wm = 'attachedValue';
obj }
使用 WeakMap,您可以將先前計算的結果與物件關聯,而不用擔心記憶體管理。下列函式 countOwnKeys()
是範例:它將先前的結果快取在 WeakMap cache
中。
const cache = new WeakMap();
function countOwnKeys(obj) {
if (cache.has(obj)) {
return [cache.get(obj), 'cached'];
else {
} const count = Object.keys(obj).length;
.set(obj, count);
cachereturn [count, 'computed'];
} }
如果我們使用物件 obj
使用這個函式,您會看到只有在第一次呼叫時才會計算結果,而第二次呼叫則會使用快取值
> const obj = { foo: 1, bar: 2};
> countOwnKeys(obj)[2, 'computed']
> countOwnKeys(obj)[2, 'cached']
在下列程式碼中,WeakMap _counter
和 _action
用於儲存 Countdown
實例的虛擬屬性的值
const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
constructor(counter, action) {
.set(this, counter);
_counter.set(this, action);
_action
}dec() {
let counter = _counter.get(this);
--;
counter.set(this, counter);
_counterif (counter === 0) {
.get(this)();
_action
}
}
}
// The two pseudo-properties are truly private:
.deepEqual(
assertObject.keys(new Countdown()),
; [])
以下是 Countdown
的使用方式
let invoked = false;
const cd = new Countdown(3, () => invoked = true);
.dec(); assert.equal(invoked, false);
cd.dec(); assert.equal(invoked, false);
cd.dec(); assert.equal(invoked, true); cd
練習:WeakMap 用於私有資料
exercises/weakmaps/weakmaps_private_data_test.mjs
WeakMap
的建構函式和四個方法與 其等效的 Map
相同
new WeakMap<K, V>(entries?: Iterable<[K, V]>)
[ES6].delete(key: K) : boolean
[ES6].get(key: K) : V
[ES6].has(key: K) : boolean
[ES6].set(key: K, value: V) : this
[ES6] 測驗
請參閱 測驗應用程式。