JavaScript ウィークマップ
1. WeakMap オブジェクトの基本
JavaScript の WeakMap は、キーと値のペアを保持するコレクションですが、キーは必ずオブジェクトである必要があります。
WeakMap の最大の特徴は、そのキーに対して「弱参照 (Weak Reference)」を保持する点にあります。
例
// WeakMap を作成
let myMap = new WeakMap();
// オブジェクトを作成
let myObj = {fname: "太郎", lname: "山田"};
// WeakMap に値をセット
myMap.set(myObj, "プレイヤー");
// WeakMap から値を取得
let type = myMap.get(myObj);2. ガベージコレクション (Garbage Collection)
JavaScript は、ガベージコレクション(Garbage Collection) と呼ばれるメモリ管理メカニズムを採用しています。
その主な役割は以下の通りです:
- メモリリソースの効率的な利用を確保する
- 使用されなくなった変数が占有しているメモリを回収する
- メモリリーク (Memory Leak) を防止する
3. 弱参照 (Weak References) の特徴
通常の Map とは異なり、WeakMap はそのキーがガベージコレクションされるのを妨げません。
プログラム内でそのオブジェクト(キー)への参照が他になくなった場合、そのオブジェクトはガベージコレクションの対象となります。
オブジェクトがメモリから回収されると、そのキーに関連付けられていたペアも自動的に WeakMap から削除されます。
例
let myMap = new WeakMap();
let myObj = {fname: "太郎", lname: "山田"};
myMap.set(myObj, "シークレット");
// オブジェクトへの参照を解除
myObj = null;
// これにより、myMap 内の myObj(およびその値)はガベージコレクションの対象となります4. キーに関する制限
WeakMap のキーとして、プリミティブ値 (Primitive values) を使用することはできません。
キーは必ずオブジェクト、または登録されていない Symbol である必要があります。
この制限はガベージコレクションの仕組みに直結しています。プリミティブ値は、オブジェクトのようにガベージコレクションによって回収される対象ではないためです。
5. オブジェクトの効率的な追跡
WeakMap のエントリは弱く保持されています。オブジェクトであるキーが「到達不能(unreachable)」になると、そのマッピングは自動的に削除されます。
これは、ガベージコレクションを妨げることなく、オブジェクトに関するメタデータを追跡するのに最適です。
5.1 訪問者の追跡
例
let text = "";
// 訪問回数を保存するための WeakMap を作成
const visitsCount = new WeakMap();
// 訪問者オブジェクトを作成
const John = {name: "ジョン", age: 40};
const Paul = {name: "ポール", age: 41};
const Ringo = {name: "リンゴ", age: 42};
const George = {name: "ジョージ", age: 43};
// 訪問を追跡
track(Paul);
track(Ringo);
track(Paul);
track(Paul);
track(John);
// 訪問者を追跡するファンクション
function track(visitor) {
let count = visitsCount.get(visitor) || 0;
count++;
visitsCount.set(visitor, count);
text += visitor.name + " さん(" + visitor.age + "歳)は " + count + " 回目の訪問です。<br>";
}5.2 自動クリーンアップ
訪問者オブジェクトへのすべての参照を削除すると、自動的にクリーンアップが行われます。
John = null;
// これで、John に関するエントリは WeakMap から自動的に削除されます6. 反復処理の不可
WeakMap は 列挙可能(Enumerable)ではありません。
forループ、forEach()、keys()などを使用して、キーや値を反復処理(Iteration)することはできません。- 要素数を確認することもできません。WeakMap には
sizeプロパティが存在しません。
7. 限定されたメソッド一覧
WeakMap で提供されているメソッドは非常に限定的です:
| メソッド | 説明 |
|---|---|
new WeakMap() | 新しい WeakMap オブジェクトを作成します |
get(key) | キーに対応する値を取得します |
set(key, value) | キーと値をセットします |
delete(key) | キーで指定された要素を削除します |
has(key) | キーが存在する場合に true を返します |
8. WeakMap による秘匿データ管理
WeakMap を利用して、外部からアクセスできないデータをオブジェクトに関連付けることができます。
例
// WeakMap を作成
const myMap = new WeakMap();
// プライベートフィールドのシミュレーション
class User {
constructor(name) {
myMap.set(this, {secret: "隠しデータ"});
this.name = name;
}
getSecret() {
return myMap.get(this).secret;
}
}
const user1 = new User("ジョン");
let secret = user1.getSecret();8.1 例の解説
WeakMap は反復処理を許可しません。そのため、外部のコードは WeakMap の中にどのオブジェクトが格納されているかを「発見」することができません。
シークレットデータを取得するには、コンストラクタ内で使用された this の参照が必要です。
外部コードは user1 や myMap にアクセスできますが、getSecret() のようなメソッドを明示的に公開しない限り、WeakMap 内部の this 参照にアクセスすることはできず、シークレット値は保護されます。
8.2 プライバシー
WeakMap は意図的にプライバシーを重視して設計されています。オブジェクトをキーとして set, get, has, delete を行うことはできますが、中身を検査(インスペクション)することはできません。
これは、JavaScript に正式な #private フィールドが導入される前に、クラスのプライベートプロパティをシミュレートするための優れたツールとして活用されてきました。