Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

Map

BaselineWidely available *

Map オブジェクトはキーと値のペアを保持し、キーが最初に挿入された順序を覚えています。キーや値には任意の値(オブジェクトとプリミティブ値)を使用することができます。

試してみましょう

const map1 = new Map();map1.set("a", 1);map1.set("b", 2);map1.set("c", 3);console.log(map1.get("a"));// Expected output: 1map1.set("a", 97);console.log(map1.get("a"));// Expected output: 97console.log(map1.size);// Expected output: 3map1.delete("b");console.log(map1.size);// Expected output: 2

解説

Map オブジェクトは、キーと値のペアのコレクションです。Map のキーは一度しか出現しませんMap の集合の中で一意です。Map オブジェクトはキーと値のペアで反復処理されます。for...of ループは、各反復処理に対して[キー, 値] という 2 つのメンバーからなる配列を返します。反復処理は挿入順 で行われます。これは、それぞれのキーと値のペアがset() メソッドによって最初にマップに挿入された順番に対応します(つまり、set() が呼ばれたときには、すでに同じ値を持つキーがマップになかったということです)。

仕様書では、「平均して、集合の要素数に対してサブリニアなアクセス時刻を提供する」マップを実装することを要求しています。したがって、複雑度が O(N) よりも高い場合、内部的にはハッシュ表(O(1) ルックアップ)、探索木(O(log(N)) ルックアップ)、あるいは他のデータ構造として表すことが可能です。

キーの等価性

キー値の等価性はSameValueZero アルゴリズムに基づいて評価されます。(以前はSameValue が使われており、0-0 が異なるものとして扱われていました。ブラウザーの互換性をチェックしてください)。これはNaNNaN と等価と見なすもので(NaN !== NaN ですが)、他の値はすべて=== 演算子の意味に従って等価性が考慮されます。

Object と Map の比較

ObjectMap は似ています。どちらもキーを値に設定したり、それらの値を受け取ったり、キーを削除したり、キーに何かが格納されているかどうかを判定したりすることができます。この意味で(そして他の組み込みオブジェクトがなかったため)、従来ObjectMap として使われてきました。

しかし、いくつかの場面でMap の方が勝るような重要な違いがあります。

MapObject
偶発的なキーMap は既定では何もキーを持っていません。明示的に設定したものだけを含みます。

Object にはプロトタイプがあります。よって既定のキーを含んでいるので、注意しないと自分のキーと衝突する可能性があります。

メモ: ES5 では、Object.create(null) を使用すると回避できますが、これはめったに行われていません。

セキュリティMap はユーザーが提供したキーと値を使用しても安全です。

ユーザーが提供したキーと値のペアをObject に設定すると、攻撃者がオブジェクトのプロトタイプを上書きできる可能性があり、 オブジェクトインジェクション攻撃につながる可能性があります。偶発的なキーの問題と同様に、これもnull-prototypeオブジェクトを使用することによって軽減することができます。

キーの型Map のキーはあらゆる値がなることができます (関数、オブジェクト、あらゆるプリミティブなど)。Object のキーは文字列またはシンボルでなければなりません。
キーの順序

Map のキーは、単純で直感的な方法で順序付けられます。すなわち、反復処理を行うと、Map オブジェクトは挿入順でキーを返します。

通常のObject のキーは現在では順序付けされていますが、以前はそうではなかったので、順序は複雑です。結果として、プロパティの順序に頼らない方が良いでしょう。

この順序は ECMAScript 2015 で初めて自身のプロパティに対してのみ定義されましたが、 ECMAScript 2020 では継承されたプロパティに対しても同様に順序が定義されています。 しかし、オブジェクトのプロパティがすべて反復処理される単一の単一のメカニズムはないことに注意してください。 (for-in は列挙可能な文字列キーのプロパティのみを含む、Object.keys は自分自身の列挙可能な文字列キーのプロパティのみを含む、Object.getOwnPropertyNames は列挙不可能な場合でも自分自身の文字列キーのプロパティを含む、Object.getOwnPropertySymbols は、Symbol キーを持つプロパティに対しても同じことを行う、など。)

大きさ

Map の中のアイテム数は、size プロパティで簡単に得ることができます。Object 内のアイテムの数を決定することは、より回りくどく、効率的ではありません。一般的な方法は、Object.keys() から返される配列のlength を通じて行う方法です。
反復処理Map反復可能 ですので、直接反復処理を行うことができます。Object では反復処理を行うのに、いくつかの形でキーの一覧を取得して、そのうえで反復処理を行う必要があります。

Object反復処理プロトコルを実装していないので、オブジェクトを JavaScript のfor...of 文を使用して直接反復処理を行うことは(既定では)できません。

メモ:

  • オブジェクトに反復処理プロトコルを実装したり、Object.keys またはObject.entries を使用して反復処理を行うことはできます。
  • for...in 文により、オブジェクトの列挙可能なプロパティを反復処理することができます。
性能

キーと値のペアを頻繁に追加したり削除したりすることが求められる場面では、性能がより良くなります。

キーと値のペアを頻繁に追加したり削除したりすることに最適化されていません。

シリアライズと解釈

シリアライズや解釈のためのネイティブな対応はありません。

(ただし、replacer 引数でJSON.stringify() を使用し、reviver 引数でJSON.parse() を使用することで、Map のために、独自のシリアライズと解釈の対応を作成することができます。 Stack Overflow の質問How do you JSON.stringify an ES6 Map? を参照してください。)

Object から JSON へのシリアライズには、JSON.stringify() を使用してネイティブに対応しています。

JSON からObject への解釈には、JSON.parse() を使用してネイティブに対応しています。

オブジェクトプロパティの設定

Map オブジェクトに対してオブジェクトプロパティを設定すると正しく動作しますが、混乱を催すことが考えられます。

たとえば、次の例は一応動作するように見えます。

js
const wrongMap = new Map();wrongMap["bla"] = "blaa";wrongMap["bla2"] = "blaaa2";console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

しかし、このようにプロパティを設定すると、 Map データ構造を使用しません。一般的なオブジェクトの機能を使用します。 'bla' の値はクエリーを行うための Map に格納されません。データにその他の操作を行うと失敗します。

js
wrongMap.has("bla"); // falsewrongMap.delete("bla"); // falseconsole.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

Map にデータを格納する正しい方法は、set(key, value) メソッドを使用する方法です。

js
const contacts = new Map();contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });contacts.has("Jessie"); // truecontacts.get("Hilary"); // undefinedcontacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}contacts.delete("Raymond"); // falsecontacts.delete("Jessie"); // trueconsole.log(contacts.size); // 1

Map 風のブラウザー API

ブラウザーのMap 風オブジェクト (または「Map 風オブジェクト」) は、多くの点でMap のようにふるまうWeb API のインターフェイスです。

Map と同様に、項目はオブジェクトに追加されたのと同じ順番で走査できます。また、Map 風オブジェクトとMap は同じ名前で同じ挙動のプロパティおよびメソッドを持ちます。しかし、Map と違い、各項目のキーと値には事前に定義された特定の型しか使用できません。

使用可能な型は、仕様書の IDL 定義で設定されています。たとえば、RTCStatsReport はキーには文字列を、値にはオブジェクトを用いなければならないMap 風オブジェクトです。これは、仕様書の IDL で以下のように定義されています。

webidl
interface RTCStatsReport {  readonly maplike<DOMString, object>;};

Map 風オブジェクトは読み取り専用のことも、読み書き可能なこともあります。(上の IDL のreadonly キーワードに注目してください)

これらのメソッドとプロパティは、キーと値の型の制約を除いて、Map の対応するエンティティと同様にふるまいます。

以下は、読み取り専用のMap 風ブラウザーオブジェクトの例です。

コンストラクター

Map()

新しいMap オブジェクトを生成します。

静的プロパティ

Map[Symbol.species]

派生クラスを生成するためのコンストラクター関数です。

静的メソッド

Map.groupBy()

与えられた反復可能な要素を、与えられたコールバック関数から返された値を使用してグループ化します。最後に返されるMap は、テスト関数から得られた一意の値をキーとして使用しており、各グループの要素の配列を取得するために使用できます。

インスタンスプロパティ

これらのプロパティはMap.prototype で定義され、すべてのMap インスタンスで共有されます。

Map.prototype.constructor

このインスタンスオブジェクトを作成したコンストラクター関数。Map インスタンスの場合、初期値はMap コンストラクターです。

Map.prototype.size

Map オブジェクトの中のキーと値のペアの数を返します。

Map.prototype[Symbol.toStringTag]

[Symbol.toStringTag] プロパティの初期値は文字列"Map" です。このプロパティはObject.prototype.toString() で使用されます。

インスタンスメソッド

Map.prototype.clear()

Map オブジェクトからすべてのキーと値のペアを削除します。

Map.prototype.delete()

Map オブジェクトに要素が存在し、削除された場合はtrue を返します。要素が存在しなければfalse を返します。その後ではMap.has(key)false を返すようになります。

Map.prototype.entries()

Map オブジェクトの各要素の[key, value] からなる 2 つの要素の配列を挿入順で含む新しいイテレーターオブジェクトを返します。

Map.prototype.forEach()

Map オブジェクトに存在するキーと値のペアの数だけ、挿入順にcallbackFn を呼び出します。thisArg 引数がforEach に渡された場合、各コールバックのthis 値として使用されます。

Map.prototype.get()

key で指定されたキーに結び付けられた値を返します。存在しない場合はundefined を返します。

Map.prototype.has()

論理値で、渡されたキーに結び付けられた要素がMap オブジェクト内に存在するかどうかを返します。

Map.prototype.keys()

Map オブジェクト内の各要素のキーが挿入順で含む、新しいイテレーターオブジェクトを返します。

Map.prototype.set()

Map オブジェクト内の渡されたキーを値に設定します。そのMap オブジェクトを返します。

Map.prototype.values()

Map オブジェクト内の各要素の値が挿入順で含む、新しいイテレーターオブジェクトを返します。

Map.prototype[Symbol.iterator]()

Map オブジェクト内の各要素の[key, value] の配列 が挿入順で含む、新しいイテレーターオブジェクトを返します。

Map オブジェクトの使用

js
const myMap = new Map();const keyString = "文字列";const keyObj = {};const keyFunc = function () {};// 値を設定するmyMap.set(keyString, "'文字列' と結び付けられた値");myMap.set(keyObj, "keyObj と結び付けられた値");myMap.set(keyFunc, "keyFunc と結び付けられた値");console.log(myMap.size); // 3// 値を取得するconsole.log(myMap.get(keyString)); // "'文字列' と結び付けられた値"console.log(myMap.get(keyObj)); // "keyObj と結び付けられた値"console.log(myMap.get(keyFunc)); // "keyFunc と結び付けられた値"console.log(myMap.get("文字列")); // "'文字列' と結び付けられた値"。 keyString === '文字列' であるためconsole.log(myMap.get({})); // undefined, keyObj !== {} であるためconsole.log(myMap.get(function () {})); // undefined, keyFunc !== function () {} であるため

NaN を Map のキーとして使用

NaN もまたキーとして使うことができます。すべてのNaN は自身と等しくない(NaN !== NaN は真)にもかかわらず、以下の例は動作します。これはNaN が互いに区別できないためです。

js
const myMap = new Map();myMap.set(NaN, "not a number");myMap.get(NaN);// "not a number"const otherNaN = Number("foo");myMap.get(otherNaN);// "not a number"

for..of を使用した Map の反復処理

マップはfor..of ループを使用して反復処理を行うことができます。

js
const myMap = new Map();myMap.set(0, "zero");myMap.set(1, "one");for (const [key, value] of myMap) {  console.log(`${key} = ${value}`);}// 0 = zero// 1 = onefor (const key of myMap.keys()) {  console.log(key);}// 0// 1for (const value of myMap.values()) {  console.log(value);}// zero// onefor (const [key, value] of myMap.entries()) {  console.log(`${key} = ${value}`);}// 0 = zero// 1 = one

forEach() で Map を反復処理

マップはforEach() メソッドを使用して反復できます。

js
myMap.forEach((value, key) => {  console.log(`${key} = ${value}`);});// 0 = zero// 1 = one

Array オブジェクトとの関係

js
const kvArray = [  ["キー1", "値1"],  ["キー2", "値2"],];// 通常の Map コンストラクターを使って、キーと値の 2 次元配列をマップに変換するconst myMap = new Map(kvArray);console.log(myMap.get("キー1")); // "値1"// 展開演算子を使って、マップをキー・値の 2 次元配列に変換するconsole.log(Array.from(myMap)); // kvArray とまったく同じ Array を表示する// あるいは展開演算子をキーまたは値のイテレーターに使って、キーまたは値のみの配列を得るconsole.log([...myMap]);// または keys() や values() のイテレーターを使用して配列に変換するconsole.log(Array.from(myMap.keys())); // ["key1", "key2"] が出力される

Map の複製と混合

Array と同様に、Map は複製することができます。

js
const original = new Map([[1, "one"]]);const clone = new Map(original);console.log(clone.get(1)); // oneconsole.log(original === clone); // false (useful for shallow comparison)

メモ:データ自身は複製されないことに注意しておいてください。

マップはキーの固有性を保持しながら混合可能です。

js
const first = new Map([  [1, "one"],  [2, "two"],  [3, "three"],]);const second = new Map([  [1, "uno"],  [2, "dos"],]);// 2 つのマップを混合します。重複するキーは後勝ちになります。// スプレッド演算子は基本的に Map を Array に変換します。const merged = new Map([...first, ...second]);console.log(merged.get(1)); // unoconsole.log(merged.get(2)); // dosconsole.log(merged.get(3)); // three

Map は Array と混合することもできます。

js
const first = new Map([  [1, "one"],  [2, "two"],  [3, "three"],]);const second = new Map([  [1, "uno"],  [2, "dos"],]);// マップと配列を混合します。重複するキーは後勝ちになります。const merged = new Map([...first, ...second, [1, "eins"]]);console.log(merged.get(1)); // einsconsole.log(merged.get(2)); // dosconsole.log(merged.get(3)); // three

仕様書

Specification
ECMAScript® 2026 Language Specification
# sec-map-objects

ブラウザーの互換性

関連情報

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp