## 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)。
- I.背景
- 1.关于本书(ES2019 版)
- 2.常见问题:本书
- 3. JavaScript 的历史和演变
- 4.常见问题:JavaScript
- II.第一步
- 5.概览
- 6.语法
- 7.在控制台上打印信息(console.*)
- 8.断言 API
- 9.测验和练习入门
- III.变量和值
- 10.变量和赋值
- 11.值
- 12.运算符
- IV.原始值
- 13.非值undefined和null
- 14.布尔值
- 15.数字
- 16. Math
- 17. Unicode - 简要介绍(高级)
- 18.字符串
- 19.使用模板字面值和标记模板
- 20.符号
- V.控制流和数据流
- 21.控制流语句
- 22.异常处理
- 23.可调用值
- VI.模块化
- 24.模块
- 25.单个对象
- 26.原型链和类
- 七.集合
- 27.同步迭代
- 28.数组(Array)
- 29.类型化数组:处理二进制数据(高级)
- 30.映射(Map)
- 31. WeakMaps(WeakMap)
- 32.集(Set)
- 33. WeakSets(WeakSet)
- 34.解构
- 35.同步生成器(高级)
- 八.异步
- 36. JavaScript 中的异步编程
- 37.异步编程的 Promise
- 38.异步函数
- IX.更多标准库
- 39.正则表达式(RegExp)
- 40.日期(Date)
- 41.创建和解析 JSON(JSON)
- 42.其余章节在哪里?