JavaScript 逆引き集 | WeakMap の利用(ガベージに強い参照)

JavaScript JavaScript
スポンサーリンク

WeakMap の基本 — new WeakMap()

WeakMap は「キーにオブジェクトだけを使える特殊なマップ」です。最大の特徴は キーとなるオブジェクトがガベージコレクション(不要メモリ解放)の対象になったら、自動的に WeakMap からも消える こと。これにより「オブジェクトに付随する追加情報」を安全に管理できます。


基本の使い方

const wm = new WeakMap();

const obj = { id: 1 };
wm.set(obj, "secret data");

console.log(wm.get(obj)); // "secret data"
console.log(wm.has(obj)); // true

// objを参照しなくなると、ガベージコレクション時にWeakMapからも消える
JavaScript
  • キー: 必ずオブジェクト(プリミティブ値は不可)。
  • 値: 任意の型。
  • メモリ管理: キーが不要になれば自動的に削除されるため、メモリリーク防止に役立つ。

WeakMap と Map の違い

特徴MapWeakMap
キー任意(文字列、数値、オブジェクト)オブジェクトのみ
ガベージコレクションキーが残るキーが解放されると自動削除
列挙for...ofkeys() で列挙可能列挙不可(内部を直接見ることはできない)
用途辞書、キャッシュ、順序付きデータオブジェクトに付随する「隠しデータ」管理

すぐ使えるテンプレート集

1) オブジェクトに付随する「秘密データ」を管理

const wm = new WeakMap();

function createUser(name) {
  const user = { name };
  wm.set(user, { loggedIn: false });
  return user;
}

const u1 = createUser("Aki");
console.log(wm.get(u1)); // { loggedIn: false }

wm.get(u1).loggedIn = true;
console.log(wm.get(u1)); // { loggedIn: true }
JavaScript
  • ポイント: userオブジェクトが破棄されれば、WeakMapのデータも自動的に消える。

2) DOM要素に関連データを付ける

const wm = new WeakMap();

function bindData(el, data) {
  wm.set(el, data);
}

function getData(el) {
  return wm.get(el);
}

// 例: DOM要素に追加情報を紐付け
const div = document.createElement("div");
bindData(div, { clicked: 0 });

div.addEventListener("click", () => {
  const d = getData(div);
  d.clicked++;
  console.log("clicked:", d.clicked);
});
JavaScript
  • ポイント: DOM要素が削除されれば WeakMap のデータも解放される。

3) クラスの「プライベートデータ」実装に利用

const privates = new WeakMap();

class Counter {
  constructor() {
    privates.set(this, { count: 0 });
  }
  inc() {
    privates.get(this).count++;
  }
  get value() {
    return privates.get(this).count;
  }
}

const c = new Counter();
c.inc();
console.log(c.value); // 1
JavaScript
  • ポイント: 外部から直接 privates にアクセスできないため、擬似的な「プライベート変数」として使える。

よくある落とし穴と対策

  • キーはオブジェクトのみ: 文字列や数値をキーにするとエラー。
    → 対策: 必ず {} やクラスインスタンス、DOM要素などをキーに。
  • 列挙できない: for...ofkeys() は使えない。
    → 対策: WeakMapは「内部を覗けない」設計。用途は「付随データの隠し管理」に限定。
  • デバッグしにくい: 中身を確認できないため、ログ出力で追えない。
    → 対策: 必要なら Map を使う。WeakMapは「ガベージに強い参照」が必要な場面だけ。

練習問題(手を動かして覚える)

// 1) オブジェクトに秘密データを紐付け
const wm = new WeakMap();
const obj = {};
wm.set(obj, "hidden");
console.log(wm.get(obj)); // "hidden"

// 2) DOM要素にクリック回数を記録
const wm2 = new WeakMap();
const btn = document.createElement("button");
wm2.set(btn, { clicks: 0 });
btn.addEventListener("click", () => {
  wm2.get(btn).clicks++;
  console.log("clicks:", wm2.get(btn).clicks);
});

// 3) クラスのプライベートデータ
const priv = new WeakMap();
class User {
  constructor(name) {
    priv.set(this, { name });
  }
  getName() {
    return priv.get(this).name;
  }
}
const u = new User("Mao");
console.log(u.getName()); // "Mao"
JavaScript

直感的な指針

  • Map: 辞書や列挙可能なデータ管理。
  • WeakMap: オブジェクトに付随する「隠しデータ」や「ガベージに強い参照」。
  • 列挙不可・オブジェクト専用: 内部を覗けない設計なので、用途は限定的。

👉 WeakMap は「オブジェクトに秘密の付加情報を持たせたい」「メモリリークを避けたい」場面で使うのがベストです。

タイトルとURLをコピーしました