Articles

WeakMap (`WeakMap`) (上級) – せっかちなプログラマのためのJavaScript(ES2021版)

(Ad, please don’t block.)

34 WeakMap (WeakMap) (上級)

  • 34.WeakMap (WeakMap)(ウィークマップ) (上級)
34.WeaakMap (ウィークマップ) (上級) (上級)1 WeakMapはブラックボックス

  • 34.2 WeakMapのキーは弱く持つ
    • 34.2.1 すべてのWeakMapのキーはオブジェクト
    • 34.2 使用例:オブジェクトに値を付ける
  • 34.3 例
    • 34.3.1 WeakMapsで計算結果をキャッシュする
    • 34.3.2 WeakMapsでプライベートデータを保持する
  • 34.3.1 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() はその例です: WeakMap cache に以前の結果をキャッシュします。

      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