## 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()),
[]);
```
 **練習:私人數據的 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>
 **測驗**
參見[測驗應用程序](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.其余章節在哪里?