WeakMap (`WeakMap`) (上級) – せっかちなプログラマのためのJavaScript(ES2021版)
34 WeakMap (WeakMap) (上級)
- 34.WeakMap (WeakMap)(ウィークマップ) (上級)
- 34.2.1 すべてのWeakMapのキーはオブジェクト
- 34.2 使用例:オブジェクトに値を付ける
- 34.3.1 WeakMapsで計算結果をキャッシュする
- 34.3.2 WeakMapsでプライベートデータを保持する
34.4 WeakMap API
WeakMapはMapと似ていますが、以下の違いがあります。
- WeakMapはブラックボックスであり、ある値にアクセスするためには、そのキーとWeakMapの両方を持っている必要があります。
34.1 WeakMapはブラックボックス
WeakMapの内部にあるものを調べることは不可能です。
- さらに、WeakMap をクリアすることもできません – 新しいインスタンスを作成する必要があります。 Mark Miller:
weakmap/key ペア値からのマッピングは、weakmap と key の両方を持つ誰かによってのみ観察または影響を受けることができます。
clear()
では、WeakMap だけを持つ人が WeakMap とキーと値のマッピングに影響を与えることができたでしょう。34.2 WeakMap のキーは weakly held
WeakMapのキーは weakly heldと言われます。 通常、あるオブジェクトが別のオブジェクトを参照する場合、後者のオブジェクトは前者が存在する限りゴミとして収集されることはありません。 もしあるオブジェクトがキーであり、他のオブジェクトを参照していなければ、WeakMap がまだ存在している間はゴミとして収集される可能性があります。 それはまた対応するエントリが削除されることにもつながります (しかし、それを観察する方法はありません)。
34.2.1 すべての WeakMap キーはオブジェクトでなければならない
すべての WeakMap キーはオブジェクトでなければなりません。 プリミティブ値を使用するとエラーが発生します:
> const wm = new WeakMap();> wm.set(123, 'test')TypeError: Invalid value used as weak map key
キーとしてプリミティブ値を使用すると、WeakMap はブラックボックスではなくなります。 しかし、プリミティブな値は決してガベージコレクトされないことを考えると、いずれにしても弱く保持されたキーから利益を得ることはなく、通常のマップを使用するのと同じです。 Bの行では、
wm
はまだ存在するが、obj
はすでにガベージコレクトされる可能性がある。 このようにオブジェクトに値をつけるという手法は、そのオブジェクトのプロパティを外部に保存しているのと同じことである。 もしwm
がプロパティであれば、前のコードは次のようになります:{ const obj = {}; obj.wm = 'attachedValue';}
34.3 Examples
34.3.1 WeakMapsによる計算結果のキャッシュ
WeakMapsにより、メモリ管理を気にせずに以前に計算した結果をオブジェクトと関連付けることができます。 次の関数
countOwnKeys()
はその例です: WeakMapcache
に以前の結果をキャッシュします。const cache = new WeakMap();function countOwnKeys(obj) { if (cache.has(obj)) { return ; } else { const count = Object.keys(obj).length; cache.set(obj, count); return ; }}
この関数をオブジェクト
obj
で使用すると、結果は最初の呼び出しに対してのみ計算され、2度目の呼び出しにはキャッシュされた値が使われます。3.2 WeakMapsでプライベートデータを保持する次のコードでは、WeakMap
_counter
と_action
を使用して、Countdown
のインスタンスの仮想プロパティの値を格納しています:const _counter = new WeakMap();const _action = new WeakMap();class Countdown { constructor(counter, action) { _counter.set(this, counter); _action.set(this, action); } dec() { let counter = _counter.get(this); counter--; _counter.set(this, counter); if (counter === 0) { _action.get(this)(); } }}// The two pseudo-properties are truly private:assert.deepEqual( Object.keys(new Countdown()), );
このように
Countdown
は使用されています:let invoked = false;const cd = new Countdown(3, () => invoked = true);cd.dec(); assert.equal(invoked, false);cd.dec(); assert.equal(invoked, false);cd.dec(); assert.equal(invoked, true);
練習問題です。 プライベートデータに対するWeakMap
exercises/weakmaps/weakmaps_private_data_test.mjs
34.4 WeakMap API
コンストラクタと
WeakMap
の4つのメソッドはMap
の同等品と同じ働きをします。-
new WeakMap<K, V>(entries?: Iterable<>)
-
.delete(key: K) : boolean
-
.get(key: K) : V
-
.has(key: K) : boolean
-
.set(key: K, value: V) : this
Quiz
Quiz appを参照せよ。
次はこちらです。 35セット(Set
) -