🗺️

Mapオブジェクトに関して

2022/01/28に公開約3,200字

どうもフロントエンドエンジニアのoreoです。今回は、JavaScriptでたまに見かけるMapに関して、改めて整理してみたいと思います。

Mapとは?

Mapは、Objectに似たキーと値をもつデータのコレクションです。Objectとは主に下記のような違いがあります(詳細後述)。

①キーにString以外を設定することができる

②キーの列挙順が保証されている

③要素数の取得が簡単

④直接的に反復処理が可能

Mapの主なメソッド

  • new Map()
    • mapコンストラクターからインスタンス化を行い、 mapオブジェクトを作成できる。
  • map.set(key, value)
    • .setメソッドの第1引数にキー、第2引数に値をそれぞれ渡して設定することができる。
  • map.get(key)
    • .getメソッドで、引数として渡したキーの値を取得できる。
  • map.delete(key)
    • .deleteメソッドで、引数として渡したキーの値を削除できる。
  • map.entries()
    • .entriesメソッドで、mapの要素であるキーと値を含んだイテレーター(反復可能オブジェクト)を返す。
  • map.size
    • .sizeメソッドで、mapの要素数を取得できる。
  • map.forEach((val,key)=>{})
    • .forEachメソッドで、反復処理が実行可能。

違い① キーにString以外を設定することができる

objectは、キーとして主にStringを使用し(*)、下記のように、String以外のNumberBooleanを使用すると文字列に変換された上でキーとして設定されます。

(*)Symbolもキーとして設定可能。

const obj = {
    キー名:"string型",
    1:"number型",
    true:"boolean型"
}
console.log(Object.keys(obj)) // [ '1', 'キー名', 'true' ] と出力

一方、Mapでは、プリミティブ型、オブジェクト型、関数などString以外のあらゆるデータ型をキーとして設定し、取得することができます。

const map = new Map();

//プリミティブ型をキーに設定
map.set('string', 'str');  //Stringのキー
map.set(1, 'num');      //Numberのキー
map.set(true, 'bool');    //Booleanのキー

console.log(map.get('string')); //「str」と出力
console.log(map.get(1));     //「num」と出力
console.log(map.get(true));   //「bool」と出力

//オブジェクト型をキーに設定
const keyObj = {}
map.set(keyObj,'obj');
console.log(map.get(keyObj));   //「obj」と出力

//関数をキーに設定
const keyFunc = function(){};
map.set(keyFunc,'func');
console.log(map.get(keyFunc));   //「func」と出力

違い② キーの列挙順が保証されている

objectでは、Object.keys()を使用した場合など、キーの列挙順は設定された順番に並ぶことが保証されていません。

const obj = {};

obj["Human"] = "hoge";
obj[-1] = "hoge";
obj["1"] = "hoge";
obj["Dog"] = "hoge";

console.log(Object.keys(obj)); //「[ '1', 'Human', '-1', 'Dog' ]」と出力

Mapでは、キーの列挙順は設定された順番になることが保証されています。なお、任意のキーを上書きしても、そのキーの順番に変化はありません。

const map = new Map();

map.set(1, "hoge");
map.set(2, "hoge");
map.set(3, "hoge");

console.log(...map.entries()); //「[ 1, 'hoge' ] [ 2, 'hoge' ] [ 3, 'hoge' ]」と出力

map.set(1, "上書き");

console.log(...map.entries()); //「[ 1, '上書き' ] [ 2, 'hoge' ] [ 3, 'hoge' ]」と出力

違い③ 要素数の取得が簡単

objectでは、Arrayに形成してから.lengthメソッドで要素数を取得したりなど、要素数の取得に一手間かかります。

一方で、mapでは、.sizeメソッドで要素数を簡単に取得することが可能です。

const map = new Map();

map.set(1, "hoge");
map.set(2, "hoge");
map.set(3, "hoge");

console.log(map.size); //「3」と出力

違い④ 直接的に反復処理が可能

objectでは、反復処理を行う場合、配列に一度加工してから行うなど、違い④の要素数の取得と同様に、一手間かかります。

一方で、mapは、イテレーターなので、for...ofを用いて反復処理が可能です。また、.forEachメソッドで、簡単に反復処理ができます。

const map = new Map();

map.set(1, "hoge");
map.set(2, "hoge");
map.set(3, "hoge");

//for...ofで列挙可能
for(const m of map){
    console.log(m);
}
//以下のように出力される
//[ 1, 'hoge' ]
//[ 2, 'hoge' ]
//[ 3, 'hoge' ]

//forEachで反復処理が可能
map.forEach((val,key)=>{
    console.log(val,key);
})
//以下のように出力される
//hoge 1
//hoge 2
//hoge 3

最後に

積極的に使っていませんでしたが、改めて整理すると便利な機能があって使いやすそうですね。反復処理が直接的に実行できるのは魅力的に思たので競プロなどで使っていきたいです!

参考

キー付きコレクション - JavaScript | MDN

Map と Set

Discussion

ログインするとコメントできます