map() は、配列の1つ1つを関数に通して、その戻り値を集めた新しい配列を返します。
元の配列は変わりません。要素数も変わりません。
上のコードは書き換えて実行できます。n * 2 を n * n にしてみてください。
何が返るのか
| 中身 | |
|---|---|
| 戻り値 | 新しい配列。長さは元と同じ |
| 元の配列 | 変わらない |
| 呼ばれる回数 | 要素の数だけ |
map() は非破壊的メソッドです。同じ配列を書き換える sort() や reverse() とは違います。
要素を変換するのが map()、要素を絞るのが
filter() です。map() で要素を減らすことはできません。
コールバック関数が受け取るもの
コールバック関数には、3つの引数が渡されます。
第2引数の index と第3引数の array は、要らなければ書かなくて構いません。
よく使う形
オブジェクトの配列から値を取り出す
いちばん多い使い道です。
下は分割代入で、必要な鍵だけ取り出す書き方です。読みやすいほうを選んでください。
中身を書き換えた新しい配列を作る
const nums = [1, 2, 3];
const doubled = nums.map(n => {
n * 2;
});
console.log(doubled);const doubled = nums.map(n => n * 2);{ をそのまま書くと関数の本体と読まれるので、({ ... }) と丸括弧で囲みます。
元の users は変わりません。
番号を振る
const nums = [1, 2, 3];
nums.map(n => console.log(n));console.log(['1', '2', '3'].map(parseInt));絞ってから変換する
filter() を先に書くと、変換する回数が減ります。
結果が同じなら、少ないほうを選んでください。
→ 配列を変換する・絞り込む
返す値が配列になるなら、flatMap() で平らにしながら変換できます。
→ 入れ子の配列を平らにする
よくある間違い
戻り値を書き忘れる
{} で囲んだら return が要ります。書かないと全部 undefined になります。
const rows = [{ n: 1 }];
const copied = rows.map((row) => row);
copied[0].n = 99;
console.log(rows[0].n);エラーにはなりません。静かに undefined が並びます。だから気づきにくい。
{} を外すか、return を書けば直ります。
戻り値を使わない
戻り値を使わないなら、map() ではなく forEach() を使います。
map() は新しい配列を作るので、捨てるなら無駄になります。
出力そのものは出ます。ただし map() が返した [ undefined, undefined, undefined ] は捨てられています。
map(parseInt) と書く
関数名だけ渡すと、引数が3つとも渡ります。
parseInt(値, 添字) として呼ばれ、第2引数が何進法かの指定になってしまいます。
1進法に 2 は無く、2進法に 3 は無いので NaN です。
Number は引数を1つしか見ないので、そのまま渡せます。
関数名をそのまま渡すときは、その関数が第2・第3引数をどう扱うか確かめてください。 → 文字列を数値に変換する
中のオブジェクトは同じものを指している
新しい配列はできますが、中身は同じオブジェクトです(浅いコピー)。 書き換えたいなら、複製してから渡します。
元の配列を変えたいとき
map() では変えられません。結果を代入し直します。
const で宣言していると代入し直せません。let を使うか、別の名前にします。
空きのある配列では呼ばれない
要素が入っていない位置(疎な配列の穴)では、コールバック関数は呼ばれません。 穴は穴のまま、結果の配列に残ります。
表示のしかたは処理系によって違います。上は Node 22.22.3 の出力です。
new Array(3) は穴が3つ並んだ配列なので、map() を通しても何も起きません。
連番を作るなら Array.from() を使ってください。
Array.from() は長さから作るので、穴を踏みません。
文字列など配列でないものを配列にしながら変換できるのも Array.from() です。
まとめ
map()は新しい配列を返す。元は変わらない。長さも変わらない- 減らしたいなら
filter()、1つにまとめたいならreduce() {}で囲んだらreturnが要る。忘れるとundefinedが並ぶ- 戻り値を使わないなら
forEach() map(parseInt)と書かない。 引数が3つとも渡る- 中のオブジェクトは同じものを指している。複製するなら
{ ...row } - 連番を作るなら
Array.from()。new Array(n).map()は動かない