【JavaScript】Mapを正しく使うためにまとめた情報

# はじめに
本記事は筆者がMapを使うために必要だと思った情報をまとめたものです。

Mapは連想配列を作成する為のものです。Mapが実装されるまではJavaScriptに連想配列が存在せず、代わりにObjectで対応していたケースが多いようですので、Objectと比較した内容をメインに記載していきます。

Mapとの比較が分かりやすいように、ObjectのProperty名はkeyとして扱っています。

# 連想配列に関わる処理をObjectからMapにする事で得られるメリット

- Objectと違い、StringとSymbol以外の任意の値もkeyに設定できる
- 要素数の取得や反復処理が比較的容易（最初からメソッドが用意されている）
- 頻繁に要素を追加・削除する場合、Objectよりもパフォーマンスが優れるケースがある
- prototypeが無い為、余計なデータが存在しない

参考: [MDN - Map - オブジェクトとマップの比較](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map)

# メソッド・実装方法

# ObjectとMapのメソッド・実装対応表

Objectで実装していた事をMapではどのようにすればよいのかをまとめました。

次の様にMapをmap変数、Objectをobj変数にセットした前提で記載しています。

```JavaScript
let obj = {};
let map = new Map();
```

|目的|Object|Map|
|:--|:--|:--|
|データのクリアー|obj = {}|map.clear()|
|データのセット|obj[key] = value <br> obj.key = value|map.set(key, value)|
|keyによるデータの取得|obj[key] <br> obj.key</p>|map.get(key)|
|keyによるデータの存在確認|key in obj|map.has(key)|
|keyによるデータの削除|delete obj[key]|map.delete(key)|
|要素数の取得|Object.keys(obj).length|map.size|
|全ての[key, value]を格納した配列の取得|Object.entries(obj)|Array.from(map.entries())|
|全てのkeyを格納した配列の取得|Object.keys(obj)|Array.from(map.keys())|
|全てのvalueを格納した配列の取得|Object.values(obj)|Array.from(map.values())|

# その他のMapのメソッド

`for...of`では必須のメソッドです。

|目的|Map|
|:--|:--|
|全ての[key, value]の配列を含むIteratorの取得|map.entries()|
|全てのkeyの配列を含むIteratorの取得|map.keys()|
|全てのvalueの配列を含むIteratorの取得|map.values()|

# 反復処理
本記事で記載はしていますが、`for...in`や`for...of`はESLintから怒られるので使わない方が良いかもしれません。
なるべく`forEach`を使用した方が良いかもしれません。
詳しくは[Airbnb JavaScriptスタイルガイド - Iterators and Generators](https://mitsuruog.github.io/javascript-style-guide/#iterators-and-generators)が参考になりますので、ご覧ください。

## Map
`for...in`は使用できない（`for...in`はObjectのプロパティに対して反復処理を行うものの為）

### forEach

※`forEach`内の関数の引数の順番に注意。

```JavaScript
// 動作確認用のデータ作成
const map = new Map();
map.set(1, 100);
map.set(2, 200);

// keyとvalueを取得
map.forEach((value, key) => console.log(`key = ${key}, value = ${value}`));
```
### for...of

```JavaScript
// 動作確認用のデータ作成
const map = new Map();
map.set(1, 100);
map.set(2, 200);

// keyとvalueを取得
for (const [key, value] of map.entries()) {
  console.log(`key = ${key}, value = ${value}`);
}

// keyを取得
for (const key of map.keys()) {
  console.log(`key = ${key}`);
}

// valueを取得
for (const value of map.values()) {
  console.log(`value = ${value}`);
}
```

## Object

参考までにObjectについても記載。

`for...of`は使用できない（Objectがiterableでない為）

Objectで`for...in`以外を使った反復処理を行う場合は、`Object.entries(obj)`等で配列に変換して`map`や`forEach`を使用する。

### map

```JavaScript
// 動作確認用のデータ作成
const obj = {
  '1': 100,
  '2': 200,
};

// keyとvalueを取得
Object.entries(obj).map((item, index) => console.log(`index = ${index}, key = ${item[0]}, value = ${item[1]}`));

// keyを取得
Object.keys(obj).map((key, index) => console.log(`index = ${index}, key = ${key}`));

// valueを取得
Object.values(obj).map((value, index) => console.log(`index = ${index}, value = ${value}`));

```

### forEach

```JavaScript
// 動作確認用のデータ作成
const obj = {
  '1': 100,
  '2': 200,
};

// keyとvalueを取得
// Object.entries(obj)で返ってくる値は[ [ '1', 100 ], [ '2', 200 ] ]
// indexが配列のインデックス、itemに配列内の値(今回だと最初が[ '1', 100 ])が格納される。
Object.entries(obj).forEach((item, index) => console.log(`index = ${index}, key = ${item[0]}, value = ${item[1]}`));

// forEachでkeyを取得
Object.keys(obj).forEach((key, index) => console.log(`index = ${index}, key = ${key}`));

// forEachでkeyを取得
Object.values(obj).forEach((value, index) => console.log(`index = ${index}, value = ${value}`));
```

### for...in

```JavaScript
// 動作確認用のデータ作成
const obj = {
  '1': 100,
  '2': 200,
};

// for...inでkeyとvalueを取得
for (item in obj) {
  console.log(`key = ${item}, value = ${obj[item]}`);
}
```