WeakMap概要

Mapと違って、キーとして使われるオブジェクトが生きているうちに、WeakMapがキーの参照を持ちますが、WeakMap以外誰にも使われていなければ、ガベージコレクションによってキーオブジェクトのメモリを解放してしまいます。つまり、キーの参照が弱い参照であり、自動的に削除される可能性があります。
次は、利用ケースでなぜWeakMapが必要なのかを理解しましょう。

利用ケース

下記execute関数が複数回に呼ばれることがあり、同じ引数objで実行される回数が10の倍数になったら、そのobj情報をシステム上に通知を行います。

// マップキーが文字列ではなく、オブジェクトです
let map = new Map();

function execute(obj){
  doSomethingWith(obj);

  // 既存の回数を取得
  const called = (map.get(obj) || 0) + 1;
  map.set(obj, called);

  // 10回目で
  if(called % 10 === 0) {
    report(obj);
  }
}
  • 上記実装の問題点

 例え、上記objがシングルページアプリケーションのDOMエレメントの場合、DOMが大量に生成されたり、破棄されたりとします。破棄されたDOMエレメントが上記回数を統計するmapのキーになっているため、GC処理対象外になり、メモリリークが発生してしまいます。
 本来は、生きているDOMエレメントを絞って統計したいにもかかわらず、死んでしまったDOMエレメントの情報も残されてしまいます。

  • 考えられるアプローチ:DOMエレメントのdeleteイベントでmapから削除する

 DOMエレメントのdeleteイベントを監視し、発生したらmapから該当objを削除するように実装すれば、メモリリーク問題が解決になります。
 ただ、そうしますと、監視マップとDOMエレメントが相互的に相手の存在を意識しなければならないし、処理も複雑になり、バグが入りやすいですね。
 いよいよWeekMapの登場です。

  • WeekMap案

GCによりキーオブジェクトの廃棄と共に、WeakMapから該当データが自動的に削除されるので、実装がシンプルになります。

// マップキーが文字列ではなく、オブジェクトです
let map = new WeakMap();

function execute(obj){
  doSomethingWith(obj);

  // 既存の回数を取得
  const called = (map.get(obj) || 0) + 1;
  map.set(obj, called); // 設定したが、GCにより自動的に削除される

  // 10回目で
  if(called % 10 === 0) {
    report(obj);
  }
}

参考記事

WeekMap(MDN)
What are the actual uses of ES6 WeakMap?

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.