
JavaScript の Map
を体系的に理解する
はじめに
Javascriptを使用していて、理解が曖昧だった箇所があり、1から学びなおすことにしました。
Mapというオブジェクトを使えば、1:1のデータ構造を簡単に扱うことができます。
C++で言うところのenum tableのような使い方ができますが、Mapは独自にメソッドを持っており、
C++で言うところのstd::vectorなどの持つ配列操作用のメソッドに近い使用感で処理を書くことができます。
1. 概要
Map
は「キーと値のペア」を保持する組み込みオブジェクトです。
主な特徴は以下です:
- 任意の型の値をキーにできる(文字列、数値、オブジェクト、関数、シンボルなど)
- キーの挿入順序を保持する
- サイズを O(1) で取得できる(
.size
プロパティ) - 反復可能(iterable) なので
for...of
やスプレッド構文で展開可能
2. 基本構文と主要メソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// 作成 const map = new Map(); // set(key, value) - 追加または更新 map.set('x', 10); map.set('y', 20); // get(key) - 値の取得(なければ undefined) console.log(map.get('x')); // 10 console.log(map.get('z')); // undefined // has(key) - キーが存在するか? console.log(map.has('y')); // true // delete(key) - エントリ削除 map.delete('x'); // clear() - 全削除 map.clear(); // size - 要素数(getterプロパティ) console.log(map.size); |
3. イテレーション
Map
は挿入順で反復可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const m = new Map([ ['a', 1], ['b', 2], ['c', 3], ]); for (const [key, value] of m) { console.log(key, value); } // 専用メソッド for (const key of m.keys()) console.log('key:', key); for (const value of m.values()) console.log('value:', value); for (const entry of m.entries()) console.log('entry:', entry); |
4. 他のコレクションとの比較
特徴 | Object | Map |
---|---|---|
キーの型 | 文字列 or シンボル | 任意の型(オブジェクト含む) |
順序保証 | 一部規定あり(仕様上複雑) | 挿入順を厳密に保持 |
サイズ取得 | O(n)(Object.keys().length ) | O(1)(.size ) |
イテレーション | for...in や Object.keys | 直接反復可能 |
5. 実践例
5-1. 頻度カウント
1 2 3 4 5 6 7 8 9 |
const counts = new Map(); const words = ['apple', 'banana', 'apple', 'orange']; for (const w of words) { counts.set(w, (counts.get(w) || 0) + 1); } console.log(counts); // Map(3) { 'apple' => 2, 'banana' => 1, 'orange' => 1 } |
5-2. キャッシュ
1 2 3 4 5 6 7 8 9 10 11 12 |
const cache = new Map(); function heavy(n) { if (cache.has(n)) return cache.get(n); const result = n * n; // 重い処理と仮定 cache.set(n, result); return result; } console.log(heavy(4)); // 計算 console.log(heavy(4)); // キャッシュから |
6. .has()
の仕様
.has(key)
はキーの存在有無を返す。
- 値が
undefined
でもキーがあればtrue
- 比較は SameValueZero(
NaN
を含めて等しいとみなす)
1 2 3 4 5 6 7 8 |
const m = new Map(); m.set('k', undefined); console.log(m.has('k')); // true console.log(m.get('k')); // undefined m.set(NaN, 'not-a-number'); console.log(m.has(NaN)); // true |
7. シリアライズ(JSON化)
Map
は直接 JSON.stringify()
すると空オブジェクト {}
になる。
保存する場合は配列に変換する:
1 2 3 4 |
const m = new Map([['a', 1], ['b', 2]]); const json = JSON.stringify([...m]); // [["a",1],["b",2]] const restored = new Map(JSON.parse(json)); |
8. 注意点
- 参照比較:オブジェクトや配列をキーにするときは同一参照でなければ一致しない
- JSON変換:直接はできない
- WeakMap:キーをオブジェクト限定にして GC と連動させたい場合は WeakMap を使う