1. 導入:なぜWeakMapが必要なのか
JavaScriptで開発をしていると、オブジェクトに紐づいたデータを保持したい場面によく遭遇します。通常はMapやObjectを使いますが、これらには「参照が残っている限りメモリが解放されない」という性質があります。もし大量のデータを扱っている場合、不要になったオブジェクトを削除し忘れると「メモリリーク」が発生し、アプリが重くなる原因になります。WeakMapは、この課題を解決し、メモリ管理を自動化してくれる非常に強力なツールです。
2. 基礎知識:WeakMapとは何か
WeakMapを一言で言えば「キーがオブジェクト限定で、かつガベージコレクション(不要なメモリの自動解放)の対象になるMap」です。
通常のMapは、キーであるオブジェクトへの参照を「強く」保持します。そのため、そのオブジェクトが他で使われなくなっても、Mapが残っている限りメモリから消えません。一方、WeakMapは「弱く」参照します。もしWeakMapのキーに指定したオブジェクトが、プログラム上のどこからも参照されなくなれば、自動的にWeakMap内のデータも破棄されます。
3. 実装・解決策
WeakMapを使うためのルールは以下の3つです。
1. キーは必ず「オブジェクト(またはシンボル)」でなければならない(文字列や数値は不可)。
2. メソッドに .size や .keys() が存在しない(列挙できない)。
3. キーが参照されなくなると、対応する値も自動で消える。
この性質を利用して、DOM要素に紐づいたデータ管理や、プライベートな変数の保持に活用します。
4. サンプルプログラム
以下のコードは、ボタン要素をクリックした回数をカウントする例です。WeakMapを使うことで、ボタンが画面から削除された際に、メモリも自動的に解放されます。
// WeakMapの初期化
const clickCounts = new WeakMap();
function trackClick(buttonElement) {
// 現在のカウントを取得(なければ0)
let count = clickCounts.get(buttonElement) || 0;
count++;
// 更新したカウントをWeakMapに保存
clickCounts.set(buttonElement, count);
console.log(`ボタンのクリック回数: ${count}`);
}
// 動作確認用
const myButton = document.createElement('button');
trackClick(myButton); // 出力: 1
trackClick(myButton); // 出力: 2
// もし myButton = null; とすると、
// WeakMap内のデータも自動的にガベージコレクションの対象になります。
5. 応用・注意点
WeakMapを使う際に最も注意すべき点は、「列挙できない」ということです。通常のMapのように、保存されているすべてのデータを取り出してループ処理(forEachなど)を行うことはできません。
そのため、WeakMapは「あるオブジェクトに対して、付随する情報を隠蔽・管理したい」という目的に特化して使いましょう。現場では、クラスのプライベートフィールドを外部から隠したい場合や、DOM要素に関連するメタデータを保持して、DOMが削除された時にメモリを確実に解放したいといったケースで非常に役立ちます。
「とりあえずMapを使えばいいや」ではなく、「そのデータはいつ不要になるか?」を意識してWeakMapを選択できるようになると、フロントエンドエンジニアとしてのレベルが一段上がりますよ!