Map・Set・WeakRef — コレクション型の使いどころ
JavaScriptには、オブジェクトや配列とは別に Map と Set という組み込みのコレクション型があります。 ES2015で追加されたこれらは、「キーの柔軟さ」や「値の一意性」といった、 従来のオブジェクト・配列では扱いにくかった要件をシンプルに解決します。
この章ではMap・Set・WeakMap・WeakSet・WeakRefの順に、それぞれの特性と実務での使いどころを整理します。
学習者オブジェクトがあるのに Map って必要なの?Set も配列で代用できそうだけど…何が違うの?
Map — あらゆる型をキーにできる連想配列
このセクションは現在執筆中です。
Set — 重複しない値のコレクション
Setは 同じ値を1つしか持たない コレクションです。 配列と似ていますが、インデックスによるアクセスはなく、「この値が含まれているか」を高速に判定できるのが特徴です。
基本の使い方
const s = new Set();
s.add(1);
s.add(2);
s.add(1); // すでに存在するので無視される(エラーにはならない)
console.log(s); // Set(2) { 1, 2 }
console.log(s.size); // 2コンストラクタに配列を渡すと、重複を取り除いた状態で初期化されます。
const sample = new Set([1, 1, 2, 3, 3]);
console.log(sample); // Set(3) { 1, 2, 3 }注意点として、console.log の出力は配列 [1, 2, 3] ではなく Set(3) { 1, 2, 3 } です。
配列として取り出したい場合はスプレッド構文か Array.from を使います。
const arr = [...sample]; // [1, 2, 3]
const arr2 = Array.from(sample); // [1, 2, 3]重複の判定ルール — 「同じ値」とは何か
Setの同値判定は SameValueZero アルゴリズムに従います。
ほぼ ===(厳密等価)と同じですが、1つだけ違いがあります。
// === での比較
console.log(NaN === NaN); // false(!)
// Setでの比較
const s = new Set();
s.add(NaN);
s.add(NaN);
console.log(s.size); // 1 — NaN同士を「同じ値」とみなす=== では NaN は自分自身と等しくないという仕様ですが、
Setでは NaN を同一の値として扱います。
これは実用上は自然な挙動で、「NaNが際限なく追加されてしまう」といった事故を防ぎます。
もう1つ押さえておきたいのは、オブジェクトは参照で比較される という点です。
const s = new Set();
s.add({ id: 1 });
s.add({ id: 1 });
console.log(s.size); // 2 — 見た目が同じでも別オブジェクトなので重複扱いにならない見た目が同じオブジェクトでも、=== で等しくなければ別の値として追加されます。
主要メソッド
| メソッド | 説明 | 戻り値 |
|---|---|---|
add(value) | 値を追加(重複なら無視) | Set自身 |
has(value) | 値が存在するか | boolean |
delete(value) | 値を削除 | 削除できたら true |
clear() | 全要素を削除 | undefined |
forEach(fn) | 各要素に対してコールバック実行 | undefined |
add はSet自身を返すので、メソッドチェーンが可能です。
const s = new Set().add(1).add(2).add(3);実務でよく使うパターン — 配列の重複排除
const ids = [1, 3, 5, 3, 1, 7];
const unique = [...new Set(ids)]; // [1, 3, 5, 7]この1行イディオムは頻出です。APIレスポンスに重複IDが含まれる場合や、 ユーザーの選択肢から重複を取り除くときなどに使います。
Setはイテラブル
for...of やスプレッド構文で回せます。挿入順が保持されます。
const s = new Set(['a', 'b', 'c']);
for (const v of s) {
console.log(v); // "a", "b", "c"
}Setの集合演算(ES2025)
ES2025で、数学的な集合演算メソッドが追加されました。
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
a.union(b); // Set { 1, 2, 3, 4 } — 和集合
a.intersection(b); // Set { 2, 3 } — 積集合(共通要素)
a.difference(b); // Set { 1 } — 差集合(aにだけある要素)
a.symmetricDifference(b); // Set { 1, 4 } — 対称差(どちらか片方にだけある要素)
a.isSubsetOf(b); // false — aはbの部分集合か
a.isSupersetOf(b); // false — aはbの上位集合か
a.isDisjointFrom(b); // false — 共通要素がないか以前はスプレッドと filter で手書きしていた処理が、ネイティブメソッドで書けるようになりました。
WeakMap・WeakSet — GCに優しいコレクション
このセクションは現在執筆中です。
WeakRef・FinalizationRegistry — 弱参照と後始末
このセクションは現在執筆中です。
ちゃんと使うためのポイント
- Setは同じ値を追加してもエラーにならず、単に無視される。サイレントに重複を弾く設計
- 同値判定は
===とほぼ同じだが、NaN同士は同一とみなされる(SameValueZero) - オブジェクトは参照比較。見た目が同じでも
===で等しくなければ別の値 - 配列の重複排除は
[...new Set(arr)]のワンライナーが定番 - Mapはキーにオブジェクトを使いたいとき、Setは一意性を保証したいときに選ぶ
次の章では、for...ofの裏側にあるイテレータとジェネレータの仕組みを解説します。