JavaScript「キー付きコレクション」完全入門(初心者向け)
初心者が 「Map / WeakMap / Set / WeakSet をどう使えばいいか」 を感覚的に理解できるように、実例・用途・注意点つきで詳しく説明します。
まず全体像をざっくりつかもう!
| コレクション | 目的 | キー or 値の型 | 重複 | 反復できる? | 弱参照? |
|---|---|---|---|---|---|
| Map | キーと値を対応づける | 何でもOK(オブジェクトもOK) | キー重複なし | ✅できる | ❌しない |
| WeakMap | オブジェクトに秘密データをひもづける | オブジェクトのみ | キー重複なし | ❌できない | ✅する |
| Set | 重複のない値の集まり | 何でもOK | 値重複なし | ✅できる | ❌しない |
| WeakSet | オブジェクトの一時マーク | オブジェクトのみ | 値重複なし | ❌できない | ✅する |
1. Map:連想配列の進化版
どんなとき使う?
- 文字列以外(オブジェクトなど)をキーにしたいとき
- データの登録・削除・存在確認を頻繁にする場合
- 要素を追加した順に処理したいとき
例:ユーザー情報を管理する
const userData = new Map();
const user1 = { name: "Alice" };
const user2 = { name: "Bob" };
userData.set(user1, { score: 80 });
userData.set(user2, { score: 95 });
console.log(userData.get(user1)); // { score: 80 }
for (const [user, info] of userData) {
console.log(`${user.name}: ${info.score}`);
}
// 出力順(挿入順)
// Alice: 80
// Bob: 95
JavaScriptよく使うメソッド
| メソッド | 説明 |
|---|---|
.set(key, value) | 値を登録する |
.get(key) | 値を取り出す |
.has(key) | 登録されているか確認 |
.delete(key) | 削除する |
.clear() | 全削除 |
.size | 登録数を取得 |
Objectとの違いまとめ
| 比較点 | Object | Map |
|---|---|---|
| キーの型 | 文字列 or シンボル | 何でもOK(オブジェクト、配列など) |
| 登録順序 | 保証されない | 保証される |
| 要素数 | Object.keys(obj).length | map.size |
| 反復方法 | for...in(注意点多い) | for...of, map.forEach() |
| 主な用途 | 静的データ定義 | 動的なキー値ペア管理 |
2. WeakMap:オブジェクト専用の「秘密の倉庫」
どんなとき使う?
- オブジェクトに プライベートデータ を持たせたい
- オブジェクトが削除されたら、自動で関連データも消えてほしい
例:プライベート情報の隠し場所
const privateData = new WeakMap();
class User {
constructor(name, secret) {
this.name = name;
privateData.set(this, { secret });
}
reveal() {
console.log(`${this.name}の秘密は:`, privateData.get(this).secret);
}
}
const alice = new User("Alice", "🍰が好き");
alice.reveal(); // Aliceの秘密は: 🍰が好き
// alice がメモリから消えたら WeakMap の中身も自動で破棄される
JavaScript⚠️ 注意!
WeakMapは キーがオブジェクトだけ。.sizeやfor...ofが使えない(中身を一覧できない)。- 手動でクリアしなくても、ガベージコレクションで自動的に整理される。
3. Set:重複のない値のコレクション
どんなとき使う?
- 配列から重複を除きたい
- 「一度だけ登録したい」データを管理したい
- 高速な「含まれているかチェック」が欲しい
例:重複を削除する
const numbers = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4]
JavaScript例:参加ユーザー管理
const participants = new Set();
participants.add("Alice");
participants.add("Bob");
participants.add("Alice"); // 重複は無視される
console.log(participants.size); // 2
participants.delete("Bob");
console.log(participants.has("Alice")); // true
JavaScriptSet の便利テク
const setA = new Set([1, 2, 3]);
const setB = new Set([2, 3, 4]);
// 和集合(どちらかに含まれる)
const union = new Set([...setA, ...setB]); // {1,2,3,4}
// 積集合(両方に含まれる)
const intersection = new Set([...setA].filter(x => setB.has(x))); // {2,3}
// 差集合(AにあってBにない)
const difference = new Set([...setA].filter(x => !setB.has(x))); // {1}
JavaScript4. WeakSet:オブジェクトを「一時的にマーク」
どんなとき使う?
- オブジェクトを「もう処理した」と記録しておく
- メモリ管理を気にせず一時的にフラグを付けたい
例:DOM要素を処理済みチェック
const processed = new WeakSet();
function handleElement(el) {
if (processed.has(el)) return; // すでに処理済みならスキップ
processed.add(el);
console.log("処理:", el.tagName);
}
// 要素例
const div = document.createElement("div");
handleElement(div);
handleElement(div); // 2回目は無視される
JavaScript⚠️ 注意!
WeakSetもオブジェクト専用。- 反復不可・
.sizeなし。 - 要素が他から参照されなくなれば自動的に破棄。
5. パフォーマンス面の目安
| 操作 | Map / Set | Object / Array |
|---|---|---|
| 挿入 | 速い(O(1)) | Array は O(n) になる場合も |
| 検索 | 速い(O(1)) | Array は O(n) |
| 削除 | 速い(O(1)) | Array は O(n) |
| 順序保持 | ✅あり | ❌不定(Object) |
💡 結論:
「キーや値を高速に探したい/消したい/順序も保ちたい」ときは
Map / Set を使うのが正解!
6. SameValueZeroとは?(NaNが扱える理由)
通常の === 比較だと:
NaN === NaN // false
JavaScriptでも Map や Set の内部ルール(SameValueZero)では:
const s = new Set([NaN]);
console.log(s.has(NaN)); // true!
JavaScriptつまり、NaN はちゃんと「同じもの」として扱われます。+0 と -0 も同じ値として扱われます。
まとめ
| 用途 | 使うべき構造 |
|---|---|
| 文字列以外のキーで値を管理したい | Map |
| オブジェクトごとの秘密情報を安全に保持したい | WeakMap |
| 重複しない値のリストを管理したい | Set |
| オブジェクトを一時的に「処理済み」などでマークしたい | WeakSet |
