JavaScript | WeakMap / WeakSet の動作(GCで自動削除)を視覚化

javascrpit JavaScript
スポンサーリンク

ここでは、WeakMap / WeakSet と Map / Set の違いをステップ実演で理解できる
「挙動比較シミュレーション」シナリオ付きデモを紹介します。


目的

同じように add()set() をしても、
WeakMap / WeakSet では「オブジェクトしかキー・値に使えない」「GC(ガベージコレクション)で自動削除される」など、
Map / Set と根本的に違う性質を理解すること。

See the Pen WeakMap / WeakSet Comparison Demo by MONO365 -Color your days- (@monoqlo365) on CodePen.

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WeakMap / WeakSet 比較デモ</title>
<style>
  body {
    font-family: "Segoe UI", sans-serif;
    background: #f8fafc;
    color: #333;
    text-align: center;
    padding: 30px;
  }
  h1 { color: #0078d7; }
  .container {
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
    gap: 20px;
    margin-top: 20px;
  }
  .panel {
    width: 45%;
    background: white;
    border-radius: 12px;
    border: 2px solid #0078d7;
    padding: 15px;
    box-shadow: 0 3px 8px rgba(0,0,0,0.1);
  }
  h2 {
    background: #0078d7;
    color: white;
    border-radius: 6px;
    padding: 5px;
  }
  button {
    padding: 8px 14px;
    margin: 6px;
    border: none;
    border-radius: 8px;
    background: #0078d7;
    color: white;
    font-weight: bold;
    cursor: pointer;
  }
  button:hover { background: #005fa3; }
  .log {
    background: #f0f9ff;
    text-align: left;
    padding: 10px;
    border-left: 5px solid #0078d7;
    border-radius: 8px;
    height: 160px;
    overflow-y: auto;
    font-size: 0.9em;
    margin-top: 10px;
  }
  .highlight { background: #fff7c2; }
</style>
</head>
<body>

<h1>🧩 Map / Set vs WeakMap / WeakSet 比較シミュレーション</h1>
<p>同じ操作を4種類に対して実行して、違いを体感してみよう!</p>

<div class="container">
  <div class="panel">
    <h2>🗺️ Map</h2>
    <div id="mapLog" class="log"></div>
  </div>
  <div class="panel">
    <h2>🔢 Set</h2>
    <div id="setLog" class="log"></div>
  </div>
  <div class="panel">
    <h2>🌿 WeakMap</h2>
    <div id="weakMapLog" class="log"></div>
  </div>
  <div class="panel">
    <h2>🍃 WeakSet</h2>
    <div id="weakSetLog" class="log"></div>
  </div>
</div>

<br>
<button id="startDemo">▶ 実演スタート</button>

<script>
const mapLog = document.getElementById("mapLog");
const setLog = document.getElementById("setLog");
const weakMapLog = document.getElementById("weakMapLog");
const weakSetLog = document.getElementById("weakSetLog");

function log(el, msg) {
  el.innerHTML += msg + "<br>";
  el.scrollTop = el.scrollHeight;
}

const myMap = new Map();
const mySet = new Set();
const myWeakMap = new WeakMap();
const myWeakSet = new WeakSet();

document.getElementById("startDemo").addEventListener("click", async () => {
  mapLog.innerHTML = "";
  setLog.innerHTML = "";
  weakMapLog.innerHTML = "";
  weakSetLog.innerHTML = "";

  log(mapLog, "🧩 Map: 文字列キーもOK");
  log(setLog, "🧩 Set: プリミティブ値もOK");
  log(weakMapLog, "🌿 WeakMap: キーはオブジェクト限定!");
  log(weakSetLog, "🍃 WeakSet: 値はオブジェクト限定!");

  await step(800);

  log(mapLog, `set("user", "Alice") ✅`);
  myMap.set("user", "Alice");
  log(setLog, `add("apple") ✅`);
  mySet.add("apple");

  log(weakMapLog, `set({}, "value") ✅`);
  const obj1 = {id: 1};
  myWeakMap.set(obj1, "value1");

  log(weakSetLog, `add({name: "obj"}) ✅`);
  const obj2 = {name: "obj"};
  myWeakSet.add(obj2);

  await step(1000);
  log(mapLog, `Map.size = ${myMap.size}`);
  log(setLog, `Set.size = ${mySet.size}`);
  log(weakMapLog, `WeakMap は size がない(非列挙)`);
  log(weakSetLog, `WeakSet も size がない(非列挙)`);

  await step(1000);
  log(weakMapLog, `<span class="highlight">obj1 への参照を破棄 → GC により削除される可能性</span>`);
  log(weakSetLog, `<span class="highlight">obj2 への参照を破棄 → GC により削除される可能性</span>`);

  await step(800);
  // 擬似的にGCされたかのような表示
  log(weakMapLog, `💨 obj1 は解放され、WeakMap から自動的に消える(実際のGCは見えない)`);
  log(weakSetLog, `💨 obj2 もGCで削除される可能性`);

  await step(1200);
  log(mapLog, `🧾 Map は手動で delete() しない限り保持`);
  log(setLog, `🧾 Set も手動で delete() しない限り保持`);
});

function step(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
</script>

</body>
</html>
HTML

実演内容(ステップ概要)

ステップ操作内容Map / Set の結果WeakMap / WeakSet の結果
1それぞれに要素を追加どんな値でもOKオブジェクトのみOK
2.size の確認値が数で取得できる非列挙(size なし)
3参照を切る何も変化なしGCで自動的に削除される可能性
4明示的削除手動で .delete() が必要不要(GCに任せる)

補足:WeakMap / WeakSet の性質

特徴Map / SetWeakMap / WeakSet
キー/値にオブジェクト使用任意オブジェクトのみ
size, keys, entries利用可利用不可(非列挙)
参照が切れると?残る自動削除(GC対象)
主な用途データ保持、ループ処理などキャッシュや一時的メモリ

このシナリオでは、
🔹 ガベージコレクション(GC) の「見えない自動削除」を擬似アニメーションで体感できます。
🔹 4つのコレクションが同じ操作でどう違うかを並列で理解できます。

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