Map と Set

Map はどんな値でも鍵にでき、Set は重複を持ちません。オブジェクトや配列と何が違うのか、同じ値とみなす基準、JSON にできない理由、集合の演算までを実行して確かめます。

実行して検証済み処理系Node 22.22.3対応ES2015難易度●●○○○目安10更新

Map鍵と値の組を持つ入れ物です。オブジェクトと似ていますが、鍵に何でも使えます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Map(2) { '国語' => 80, '数学' => 95 } 80 undefined true 2
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Set(3) { 1, 2, 3 } Set(2) { 'あ', 'い' }

Set重複しない値の集まりです。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
{ '1': '文字' } [ '1' ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
2 数 文字

オブジェクトとの違い

オブジェクトの鍵は、文字列か Symbol にしかなりません。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true false
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 1 2

1'1'同じ鍵になり、後から書いたほうで上書きされました。

Map なら別々に持てます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
見つかる undefined
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'b', 'a' ] [ 2, 1 ] [ [ 'b', 2 ], [ 'a', 1 ] ]
オブジェクト Map
鍵にできるもの 文字列 / Symbol 何でも
件数 Object.keys().length size
順番 整数キーが先に来る 入れた順
初めから入っているもの toString など
JSON そのまま書ける 書けない

継承したものが混ざらない

オブジェクトには、書いた覚えのない鍵が最初から存在します。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
国語 80 数学 95
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
a 1

利用者の入力を鍵にする(辞書として使う)なら、Map のほうが安全です。 オブジェクトだと、toStringconstructor という入力が来たときに壊れます。

何を「同じ」とみなすか

Map の鍵と Set の値は、SameValueZeroという基準で比べます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Map(2) { 'a' => 1, 'b' => 2 } { a: 1, b: 2 }
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Map(3) { 'あ' => 3, 'い' => 1, 'う' => 1 }
  • NaN は自分自身と同じとみなされます(=== では false なのに)
  • 0-0 は同じ
  • 見た目が同じでも、別のオブジェクトは別

オブジェクトは中身ではなく、そのもので比べられます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Set(4) { 1, 2, 3, 4 } Set(2) { 2, 3 } Set(1) { 1 } true
javascript
console.log(JSON.stringify(new Map([['a', 1]])));
{}

同じ形を作り直しても取り出せません。 これが Map のいちばんの落とし穴です。

配列から重複を取り除く

順番と取り出し方

どちらも入れた順を保ちます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[["a",1]] {"a":1}
javascript
console.log(new Set([1, 2, 3]).length);
undefined

for...of で回すと、鍵と値の組が来ます。

forEach()値が先、鍵が後です。配列の forEach() と同じ並びに揃えてあります。

引数の順を取り違えやすいので、for...of のほうを勧めます。

オブジェクトとの行き来

Object.entries()Object.fromEntries() で往復できます。 → Object.keys() / values() / entries()

数えるのに向いている

Map のいちばん多い使い道です。

get()undefined を返すので、??0を補います。

集合の演算

Set 同士の計算ができます(ES2025)。

比較的新しい機能です。Node 22 / Chrome 122 / Safari 17 / Firefox 127 より前では使えません。

よくある間違い

そのまま JSON.stringify() に渡す

中身が消えます。 例外も出ません。

MapSet も、JSON にそのままは書けません。配列かオブジェクトに直してください。

鍵が文字列だけなら Object.fromEntries()、 そうでないなら組の配列にして保存します。

length を見る

MapSetsize です。配列と混ぜないでください。

何でもかんでも Map にする

鍵が文字列で決まっていて、件数も少ないなら、オブジェクトのほうが読みやすくなります。 Map を選ぶのは、次のどれかに当てはまるときです。

  • 鍵が文字列以外(オブジェクト・数値を区別したい)
  • 鍵が実行時に決まる(利用者の入力・外部データ)
  • 出し入れが頻繁で、件数を数えたい

まとめ

  • Map の鍵は何でもよい。オブジェクトは文字列に変えられてしまう
  • 比較はSameValueZeroNaN は同じ、別オブジェクトは別
  • どちらも入れた順を保つ。件数は size
  • forEach()値が先for...of のほうが間違えにくい
  • JSON にそのままは書けない。 黙って {} になる
  • 利用者の入力を鍵にするなら Map。継承した鍵が混ざらない

この記事の根拠

  1. Map Objects — ECMAScript® 2026 Language Specificationtc39.es
  2. Set Objects — ECMAScript® 2026 Language Specificationtc39.es
  3. Set — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)