WeakMap
)(进阶)WeakMaps 类似于 Maps,但有以下区别:
接下来的两节 将更详细地研究这意味着什么。
无法检查 WeakMap 中的内容。
这些限制实现了一个安全属性。引用 Mark Miller 的话:
只有同时拥有 weakmap 和键的人才能观察或影响 weakmap/键对值的映射。使用
clear()
,只有 WeakMap 的人就可以影响 WeakMap 和键到值的映射。
WeakMap 的键被称为是被弱引用的:通常,如果一个对象引用了另一个对象,那么只要前者存在,后者就不能被垃圾回收。对于 WeakMap,情况就不同了:如果一个对象是一个键,并且没有被其他地方引用,那么即使 WeakMap 仍然存在,它也可能被垃圾回收。这也导致相应的条目被删除(但无法观察到这一点)。
所有 WeakMap 键必须是对象。如果您使用原始值,则会出错:
> const wm = new WeakMap();
> wm.set(123, 'test')TypeError: Invalid value used as weak map key
如果将原始值作为键,WeakMaps 将不再是黑盒。但是,鉴于原始值永远不会被垃圾回收,因此您无论如何都不会从弱引用的键中获益,并且可以像使用普通 Map 一样使用它。
这是 WeakMaps 的主要用例:您可以使用它们将值从外部附加到对象——例如:
const wm = new WeakMap();
{const obj = {};
.set(obj, 'attachedValue'); // (A)
wm
}// (B)
在 A 行,我们将一个值附加到 obj
。在 B 行,即使 wm
仍然存在,obj
也可能已经被垃圾回收。这种将值附加到对象的技巧等效于将该对象的属性存储在外部。如果 wm
是一个属性,则前面的代码将如下所示:
{const obj = {};
.wm = 'attachedValue';
obj }
使用 WeakMaps,您可以将先前计算的结果与对象相关联,而不必担心内存管理。以下函数 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']
在以下代码中,WeakMaps _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
练习:用于私有数据的 WeakMaps
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]测验
请参阅 测验应用程序。