始めに
JavaScriptを勉強中なのですが、いつも map の書き方を思い出すのに少し時間がかかるので、備忘録としてまとめました。
特に、いわゆる「連想配列(key/value)」で混乱しやすいので、配列 / オブジェクト / Map の3パターンを並べて整理します。

同じように「あれ?どう書くんだっけ?」となってる方の助けになれば嬉しいです!
結論
mapとはズバリ…

各要素を変換して、新しい配列を返すメソッド!
mapとは
mapメソッドは、配列の各要素に対して同じ関数を適用し変換できるメソッドです。
元の配列は変換されないので、元の内容を維持しながら、変換後の新しい配列を作ることができます。
基本構文
まずは基本構文を見てみましょう!
Array.prototype.map(callbackFn);
引数 | 内容 |
---|---|
callbackFn | 配列の各要素に対して実行する関数。 この関数で処理され戻ってきた値は、新しい配列の要素として追加される。 |
引数に「どんな変換処理をしたいのか?」を渡すことで、各要素が引数の処理の通り変換され、新しい配列を作ることができるんですね。
参考) MDN Web Docs
配列に対しての使い方(基本例)
では基本として、数値の配列に対してmapメソッドを使ってみます。
const numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 各要素を2倍する
const newList = numList.map((n) => n * 2);
console.log("newList⇒", newList);
console.log("numList⇒", numList);
実行結果はこんな感じ↓

newListのほうはすべての要素が2倍になっていますね。
一方で元の配列であるnumListのほうは値が変わっていません。
これらのことからmapメソッドは、
- 配列のすべての要素を変換できる
- 元の配列は変換されない
ということが分かります。
連想配列に対しての使い方
連想配列とは?
mapの話をする前に、連想配列についておさらいしておきます。
JavaScriptでの連想配列と呼ばれるものの書き方はいくつかあるようです。
パターンごとに整理します。
配列の中にオブジェクト
よく使われる形で、配列の中に、{Key:value}のセットになったオブジェクトをいくつも入れている…という形式です。
これは配列なので、普通にmapメソッドを使うことができます。
const users = [
{ id: 1, name: "taro" },
{ id: 2, name: "hanako" },
{ id: 3, name: "jiro" },
];
console.log(users.map((user) => user.id)); // idだけの配列にする
console.log(users.map((user) => user.name)); // nameだけの配列にする
実行結果はこんな感じ↓

オブジェクトをKey:value形式に
{Key: value}をそのまま変数に入れる形式です。
これはオブジェクトになるので、mapメソッドを使うことができません。

この場合は、オブジェクトを[Key, value]の配列にすることでmapメソッドを使えるようになります。
const priceTable = { apple: 150, banana: 200, orange: 300 };
// オブジェクトを配列に変換した結果を表示
console.log(Object.entries(priceTable));
// valueを10%プラスした値に変換
console.log(
Object.entries(priceTable).map(([k, v]) => [k, Math.round(v * 1.1)])
);
実行結果はこんな感じ↓

1行目でオブジェクトを配列にした結果を表示しています。
確認してみると、元々オブジェクトだったものが配列になっていますね。
配列になったのでmapが使えるようになります。
オブジェクトを配列にする場合によく使われるのはこちら!
メソッド | どんなことができる? |
---|---|
Object.entries(obj) | オブジェクトを[Key, value]の配列にしてくれる |
Object.keys(obj) | オブジェクトのKeyを配列にしてくれる |
Object.values(obj) | オブジェクトのvalueを配列にしてくれる |
Mapオブジェクト
Mapオブジェクトとは、ES2015で追加されたKeyとvalueのペアを保存できるオブジェクトです。こちらもオブジェクトなので、mapは使えません。
[…配列やオブジェクト]と記述するスプレッド構文というものを使って[Key, value]という配列の形にすることでmapが使えるようになります。
const priceTable = new Map([
["apple", 150],
["banana", 200],
["orange", 300],
]);
// スプレッド構文でpriceTableを配列に
// valueを10%マイナスした値に変換
console.log([...priceTable].map(([k, v]) => [k, Math.round(v * 0.9)]));
実行結果はこんな感じ↓

元の配列が書き変わることもある…!?
mapは元の配列を書き換えることはありません。
しかし、mapのコールバックの中でオブジェクトを直接いじると、元の配列を書き換えてしまうんです!
『中身をその場で書き換えること』を『ミューテート』と言います。
const users = [
{ name: "A", active: false },
{ name: "B", active: false },
];
const out1 = users.map((u) => {
// u は users の要素オブジェクトそのものを指す参照
u.active = true; // ← 参照先の中身を書き換えた(ミューテート)
return u; // out1 には “同じオブジェクトの参照” が入る
});
console.log(users[0] == out1[0]); // true(同じオブジェクト)
console.log(users[0].active);
実行結果はこんな感じ↓

元の配列も、新しい配列もどちらもtrueになってしまいました。
これは配列の要素が「参照(オブジェクトなど)」だと起こります。
逆に基本例で出したような、要素が「数値」の場合は起こりません。
参照と値(プリミティブ)の違いはまた別途記事にしたいと思います!
参照の値に対してmapを使うときには、スプレッド構文を使うことでミューテートを回避できます。
書き方は『Mapオブジェクト』のコード例をご参考ください。

配列内の値が「数値か?そうじゃないか?」は気を付けないといけないですね💦
まとめ
読んでいただきありがとうございました!
最後にまとめです🌟

まだまだ学習途中なので、間違っている部分がありましたら
教えていただけると嬉しいです!🙏
コメント