JavaScript Map でキーと値を順序付き管理

JavaScript の Map オブジェクトはキーと値のペアを保存し、キーにオブジェクト、関数、プリミティブなど任意の値を使えます。挿入順で反復したいとき、文字列以外のキーが必要なとき、追加と削除が多いときに使います。プレーンオブジェクトと違って、Map のキーは継承されたプロトタイププロパティの影響を受けないため、動的な文字列キーでも意図しない衝突を避けられます。

キーと値を保存する JavaScript Map の例

出力:

ここに出力が表示されます...

出力:

95
false
2

この例の仕組み

  1. new Map() は空の map を作成します。new を付けずに Map() を呼ぶと TypeError が発生します。
  2. set はキーと値のペアを追加し、Map インスタンス自身を返します。これにより map.set("a", 1).set("b", 2) のようにチェーンできます。既存キーに set すると、反復位置を変えずに値だけ上書きします。
  3. get は保存された値を返し、キーが存在しない場合は undefined を返します。undefined が値として設定されている場合と未登録キーを区別するには has を使います。
  4. size は現在のエントリ数を返します。オブジェクトのように Object.keys(obj).length を使う必要はありません。

JavaScript Map でよくある間違い

set/get ではなくブラケット記法を使う:

悪い例:

const map = new Map();
map["キー"] = "値";
console.log(map.get("キー")); // undefined

正しい例:

const map = new Map();
map.set("キー", "値");
console.log(map.get("キー")); // "値"

ブラケット記法は Map エントリではなく、Map インスタンス上のオブジェクトプロパティを設定します。gethassize はそれを参照しません。

オブジェクトキーが構造で等価比較されると考える:

悪い例:

const map = new Map();
map.set({id: 1}, "太郎");
console.log(map.get({id: 1})); // undefined

正しい例:

const key = {id: 1};
map.set(key, "太郎");
console.log(map.get(key)); // "太郎"

Map はキーの等価性に SameValueZero を使います。オブジェクトでは参照同一性で比較されるため、見た目が同じオブジェクトリテラルでも別キーとして扱われます。

JavaScript Map vs Object

MapObject
キーの型任意の値(オブジェクト、関数、プリミティブ)文字列と Symbol のみ
反復順序挿入順(保証される)ほぼ挿入順だが、整数風キーは先に並ぶ
サイズmap.sizeObject.keys(obj).length
プロトタイプ衝突なしtoStringconstructor などと衝突する可能性がある
JSON シリアライズObject.fromEntries で手動変換JSON.stringify をそのまま使える

キーが文字列以外のとき、エントリの追加と削除が多いとき、信頼できないキーを扱うときは Map を使います。固定形のレコードや JSON 化が必要なデータにはプレーンオブジェクトを使います。 オブジェクトを使いたいがプロトタイプキー衝突を避けたい場合は、Object.create(null) を基盤オブジェクトにします。

FAQ

JavaScript Map は挿入順を保持しますか?

はい。Map はエントリを最初に挿入した順で反復します。既存キーに set() した場合は値だけ更新され、元の位置は維持されます。キーを削除して再追加すると末尾へ移動します。

JavaScript Map でオブジェクトをキーにできますか?

はい。ただし Map はオブジェクトキーを構造ではなく参照で比較します。同じプロパティを持つ別オブジェクトは別キーです。変数に参照を保存し、その同じ参照を setget の両方で使ってください。

JavaScript Map をオブジェクトや JSON に変換するには?

Object.fromEntries(map) を呼ぶとプレーンオブジェクトを作成できます。ただし有効なのは、すべてのキーが文字列または Symbol の場合です。文字列以外のキーがある場合は、エントリ配列を JSON.stringify([...map]) でシリアライズします。

JavaScript Map と JavaScript の map() 関数の違いは?

Map はデータを保存・検索するためのキーと値のコレクションです。JavaScript の map() 関数(Array.prototype.map)は、各要素にコールバックを適用して新しい配列を返す配列メソッドです。名前は同じですが用途は異なります。