ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 31\. WeakMaps(`WeakMap`) > 原文: [http://exploringjs.com/impatient-js/ch_weakmaps.html](http://exploringjs.com/impatient-js/ch_weakmaps.html) WeakMaps 与 Maps 类似,但有以下区别: * 它们可用于将数据附加到对象,而不会阻止这些对象被垃圾回收。 * 它们是黑盒子,只有拥有 WeakMap 和密钥才能访问值。 接下来的两节将更详细地研究这意味着什么。 ### 31.1。通过 WeakMaps 将值附加到对象 这是通过 WeakMap 将值附加到对象的方法: ```js const wm = new WeakMap(); { const obj = {}; wm.set(obj, 'attachedValue'); // (A) } // (B) ``` 在 A 行中,我们将值附加到`obj`。在 B 行中,`obj`可以被垃圾收集。 WeakMaps 的显着特征是`wm`不会阻止`obj`被垃圾收集。将值附加到对象的这种技术等同于在外部存储该对象的属性。如果`wm`是属性,则前面的代码如下所示。 ```js { const obj = {}; obj.wm = 'attachedValue'; } ``` #### 31.1.1。 WeakMap 的键是弱的 据说 WeakMap 的键是 _ 弱保持 _:通常,对对象的引用会阻止对象被垃圾收集。但是,WeakMap 键没有。此外,WeakMap 条目(其密钥是垃圾收集的)也(最终)被垃圾收集。 弱键只对对象有意义。因此,您只能将对象用作键: ```js > const wm = new WeakMap(); > wm.set(123, 'test') TypeError: Invalid value used as weak map key ``` ### 31.2。 WeakMaps 为黑盒子 检查 WeakMap 中的内容是不可能的: * 例如,您不能迭代或循环键,值或条目。而你无法计算大小。 * 此外,您无法清除 WeakMap - 您必须创建一个新的实例。 这些限制启用了安全属性。引用 [Mark Miller](https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-11/nov-19.md#412-should-weakmapweakset-have-a-clear-method-markm) :“弱映射/密钥对值的映射只能由同时具有弱映射和密钥的人来观察或影响。使用`clear()`,只有 WeakMap 的人才能够影响 WeakMap 和键值映射。“ ### 31.3。例子 #### 31.3.1。通过 WeakMaps 缓存计算结果 使用 WeakMaps,您可以将先前计算的结果与对象相关联,而无需担心内存管理。以下函数`countOwnKeys()`是一个示例:它将以前的结果缓存在 WeakMap `cache`中。 ```js const cache = new WeakMap(); function countOwnKeys(obj) { if (cache.has(obj)) { return [cache.get(obj), 'cached']; } else { const count = Object.keys(obj).length; cache.set(obj, count); return [count, 'computed']; } } ``` 如果我们将此函数与对象`obj`一起使用,您可以看到结果仅针对第一次调用计算,而缓存值则用于第二次调用: ```js > const obj = { foo: 1, bar: 2}; > countOwnKeys(obj) [2, 'computed'] > countOwnKeys(obj) [2, 'cached'] ``` #### 31.3.2。通过 WeakMaps 保存私人数据 在以下代码中,WeakMaps `_counter`和`_action`用于存储`Countdown`实例的虚拟属性数据: ```js let _counter = new WeakMap(); let _action = new WeakMap(); class Countdown { constructor(counter, action) { _counter.set(this, counter); _action.set(this, action); } dec() { let counter = _counter.get(this); if (counter < 1) return; counter--; _counter.set(this, counter); if (counter === 0) { _action.get(this)(); } } } // The two pseudo-properties are truly private: assert.deepEqual( Reflect.ownKeys(new Countdown()), []); ``` ![](https://img.kancloud.cn/3e/d5/3ed5755d562179ae6c199264f5e21157.svg) **练习:私人数据的 WeakMaps** `exercises/maps-sets/weakmaps_private_data_test.js` ### 31.4。 WeakMap API `WeakMap`的构造函数和四种方法与[的`Map`等价物](ch_maps.html#quickref-maps)的作用相同: * `new WeakMap<K, V>(entries?: Iterable<[K, V]>)` <sup>[ES6]</sup> * `.delete(key: K) : boolean` <sup>[ES6]</sup> * `.get(key: K) : V` <sup>[ES6]</sup> * `.has(key: K) : boolean` <sup>[ES6]</sup> * `.set(key: K, value: V) : this` <sup>[ES6]</sup> ![](https://img.kancloud.cn/ff/a8/ffa8e16628cad59b09c786b836722faa.svg) **测验** 参见[测验应用程序](ch_quizzes-exercises.html#quizzes)。