JavaScriptで配列を扱うなら、forEachは副作用を伴う反復処理、mapは値を変換して新しい配列を作る処理に使います。戻り値を使わないならforEach()、戻り値を渡すならmap()です。
その違いを押さえると、console.log()の確認、DOM反映、APIレスポンス整形を分けやすくなります。初心者がつまずきやすいのは、forEachの戻り値を配列として使う点と、mapを単なるループにする点でしょう。
MDNのArray.prototype.forEach()は各要素に関数を一度ずつ実行し、戻り値はundefinedです。一方、Array.prototype.map()は各要素に関数を適用し、その結果から新しい配列を作ります。
- JavaScript: ECMAScript 2024 相当の構文
- ブラウザ: Google Chrome 126 以降、Firefox 127 以降、Safari 17 以降
- Node.js: 20 LTS 以降
forEachとmapの戻り値と副作用の違いcallbackFn、index、arrayの使い方NodeList、DOM、addEventListenerでの反復処理Promise.allとmapを組み合わせた非同期処理filter、reduce、findとの実用的な使い分け
forEachとmapの基本を押さえよう!
結論は、処理の目的が「実行」ならforEach、「変換」ならmapです。最小コードで比べると、forEach()は画面やログなど外側へ影響を出し、map()は戻り値として新しいArrayを返す点がはっきり分かります。
結果: 期待される出力は、forEach側で果物名が順番に表示され、map側で文字列に変換された配列が表示される形です。
この違いは、コードを読む人にも処理意図を伝えます。forEachが出てきたら「各要素に対して何かを実行する」と読み、mapが出てきたら「各要素から別の値を作る」と理解すると整理しやすいでしょう。
そのため、JavaScriptのforEachでreturnを活用する6つのテクニックのようにreturnを扱う場合でも、forEachの返値は使えません。returnはコールバックから抜けるだけで、反復全体を止める仕組みではありません。
forEachの基本構文
forEach()はcallbackFnにelement、index、arrayを渡します。第1引数だけでも使えますが、要素番号や配列全体を参照したい場面では第2引数と第3引数が役立つ。
結果: 期待される出力は、各点数に件数が付き、最後の要素だけendが付く形です。
このときarray.lengthを参照できるため、前後の要素と比較する処理にも使えます。ただし、forEachは途中で自然にbreakできないため、条件に合う要素を探すだけならfind()やsome()のほうが扱いやすい。
mapの基本構文
map()は各要素から戻した値を集めて、新しい配列を返します。元の配列を直接変えずにid、name、createdAtなどの形式を整えられるため、表示用データの作成と相性がよい。
結果: 期待される出力は、namesに名前だけの配列、usersに元のオブジェクト配列が表示される形です。
一方、mapのコールバック内でconsole.log()だけを実行し、戻り値を使わない書き方は意図が読み取りにくくなります。その処理は副作用が目的なので、forEachへ寄せるほうが自然です。
| 観点 | forEach | map | 判断基準 | 関連する構文 |
|---|---|---|---|---|
| 戻り値 | undefined | 新しい配列 | 戻り値を使うならmap | return |
| 主な目的 | 副作用の実行 | 値の変換 | ログやDOMはforEach | console.log |
| 元配列 | 書き方次第で変更可能 | 直接変更しない設計にしやすい | 不変性を保つならmap | ... |
| 途中終了 | 通常は不可 | 変換用途なので不可 | 探索ならfind | some |
| 非同期 | awaitを待つ用途に不向き | Promise配列を作りやすい | 並列ならPromise.all | async |
| DOM操作 | 複数要素への反映に向く | 表示データの生成に向く | 画面変更はforEach | querySelectorAll |
| チェーン | つなげにくい | つなげやすい | 加工の連鎖はmap | filter |
| 型変換 | 副作用として代入しがち | 変換結果を集めやすい | 文字列数値変換はNumber | Number() |
forEachとmapはどう使い分ける?
使い分けの軸は、処理後に配列が必要かどうかです。forEachはclassList.add()、addEventListener()、ログ出力のように外側へ作用する処理で読みやすく、mapはAPIデータを画面用の形へ変える処理で意図が伝わります。
具体的には、JavaScriptイベント徹底解説!30個の使い方と応用例で扱うイベント登録はforEachと相性があります。反対に、一覧ラベルや集計用の数値はmapで新しい配列にすると後続処理へ渡しやすい。
結果: 期待される出力は、forEachで個別の行が表示され、mapで文字列配列が表示される形です。
そのため、画面やログに出すだけならforEach、作った文字列を保存・結合・描画へ回すならmapと考えます。処理目的を変数名へ反映すると、numberLabelsの意味も明確になる。
💡 Tips:forEachとmapの迷いは「戻り値を使うか」でほぼ整理できます。新しい配列が不要ならforEach、必要ならmapという基準に寄せると、読み手が処理の意図を追いやすくなるのが基本です。
一方、実装パターンとしてよく見るのは、mapで必要な項目だけに変換してから、forEachで表示や送信を行う流れです。変換と副作用を分けると、片方の変更がもう片方へ影響しにくくなるのが基本です。
結果: 期待される出力は、名前と年齢を整形した文字列がユーザーごとに表示される形です。
この分離はテストにも効きます。userCardsは入力と出力の比較がしやすく、表示処理は副作用だけに絞れます。
実践で使える!forEach活用テクニック5選
forEachは配列を回しながら外側へ影響を出す場面で使いるのが目安です。特に押さえたいのは、インデックス付き処理、DOM操作、オブジェクト更新、非同期処理、大量データへの配慮です。
配列の各要素を簡単操作
これらの処理で最も素直なのは、要素とindexを一緒に扱う書き方です。番号付き表示、入力順の保持、隣接要素との比較など、単純なfor文で書いていた処理を読みやすく置き換えられます。
結果: 期待される出力は、id、name、labelを持つオブジェクト配列です。
ただし、この例はcart.push()という副作用を使っています。新しい配列を作るだけならmapのほうが短く、変数の再代入や外部配列の変更も避けやすいでしょう。
DOM操作をスッキリ書く
document.querySelectorAll()が返すNodeListには、多くの現代的なブラウザでforEachを使えます。ボタンにクラスを付ける、イベントを登録する、入力欄をまとめて検査する処理では、戻り値より副作用が主役になる。
結果: 期待される表示は、対象ボタンへis-readyクラスが付き、クリック時にis-activeが切り替わる状態です。
この処理は、JavaScriptにおけるイベントハンドラを完全ガイド!20選の実践サンプルコード付きで扱うイベント登録の基礎にもつながります。ただし、古い環境ではArray.from()で配列化する選択肢もあります。
オブジェクト配列の処理
オブジェクト配列をforEachで処理すると、既存オブジェクトへ計算結果を追加できるのがポイントです。もっとも、元データを変える設計になるため、変更を許容するデータなのかを先に決める必要があるのが目安です。
結果: 期待される出力は、各ユーザーにaverageプロパティが追加された配列です。
逆に、元配列を保ったまま平均点付きの配列を作りたい場合はmapを使います。...のスプレッド構文で既存プロパティを展開し、新しいaverageだけを追加すると意図が明確になる。
非同期処理との組み合わせ
forEachのコールバックにasyncを付けても、外側のforEachはawaitを待ちません。MDNのforEach()解説でも、プロミスを待たない点が注意点として示されています。
結果: 期待される出力は、すべてのfetchが完了したあとに各レスポンスのstatusが表示される形です。
そのため、並列に取得したい場合はmapでPromise配列を作り、Promise.all()へ渡します。順番に待ちたい場合はfor...ofとawaitを組み合わせるほうが読みやすい。
forEach内のasync関数は、反復全体の完了を表すPromiseを返しません。完了待ちが必要な処理ではPromise.allまたはfor...ofを検討します。パフォーマンスを意識した使い方
大量データを扱うときは、forEachそのものより、ループ内で何を作るかが効きますし、ここがポイントです。毎回新しい関数や大きなオブジェクトを作ると、メモリ確保と破棄が増える可能性があるのがポイントです。
一般に、DOM更新はまとめて行い、計算済みの値は変数へ保持します。ただし、負荷はデータ量や処理内容で変わるため、読みやすさと不要な生成の削減を基準にするとよい。
現場で役立つ!mapメソッド実践テクニック5選
mapは、元データを表示用・送信用・集計用の別形式へ変えるときに使いるのが一般的です。APIレスポンスのキー変換、ネストした配列の整形、条件付きの値追加、メソッドチェーンなど、戻り値を中心に設計できる点が特徴です。
データ変換の基本パターン
APIのレスポンスは、サーバー側の命名規則に合わせてsnake_caseになっていることがあります。フロントエンド側でcamelCaseへ寄せるなら、mapで表示に近い形へ変換すると後続処理が読みやすくなります。
結果: 期待される出力は、user_idがid、user_nameがname、created_atがDateに変換された配列です。
この変換を早い段階で済ませると、テンプレート側でuser.user_idとuser.idが混在しにくくなります。日付表示はtoLocaleDateString()で表示専用の値を作れます。
オブジェクト配列の変換術
注文データのようにネストした配列を含む場合も、外側のmapと内側のreduceを組み合わせると集計値を作れますが、これは押さえたい点です。quantityとpriceから小計を出し、注文単位の合計へ変換する流れです。
結果: 期待される出力は、注文ID、合計金額、商品数を持つ集計用オブジェクトの配列です。
ただし、itemsが存在しない可能性があるデータでは?.のオプショナルチェーンや??のNull合体演算子を使います。欠損データを空配列として扱う設計にすれば、画面側の条件分岐を減らせるでしょう。
複雑なデータ構造の整形
ツリー構造をセレクトボックスやメニュー用の形式に変える場合、親と子を同じルールで整形すると扱いやすくなります。childrenがないノードもあり得るため、存在確認を変換式に含めるのが現実的です。
結果: 期待される出力は、親部署と子部署がlabel、value形式にそろった配列です。
同様に、ファイル名や拡張子の整形でもmapは使えます。JavaScriptで拡張子を活用する方法12選!初心者でも簡単にできる方法を紹介のような文字列処理では、split()やslice()で分解した値を配列へ戻せます。
条件付きマッピング
条件によって値を変えたいときも、mapの戻り値をオブジェクトにすると情報をまとめられますし、これが一つの目安です。roleから権限を作る、scoreから判定を作る、といった変換では三項演算子やifを使い分けますし、ここがポイントです。
結果: 期待される出力は、各メンバーにcanEditとdisplayNameが追加された配列です。
このとき、条件が増えすぎるとmapの中身が読みにくくなります。判定ロジックをgetPermission()やformatDisplayName()のような関数へ分けると、変換の流れを保ったまま個別条件を管理できます。
チェーンでの活用法
mapはfilterやreduceと組み合わせると、抽出、変換、集計を一続きで書けるのが現実的です。ただし、チェーンが長いと読み手が中間状態を追いにくくなるため、意味のある単位で変数に分ける判断も必要です。
結果: 期待される出力は、販売データだけを合計した3000です。
一方、日付配列を画面用データへ変換する処理では、JavaScriptでカレンダーを作成!サンプルコード10選で簡単理解のように、日付、曜日、表示ラベルをmapで整形できます。表示側は整形済みデータを受け取るだけです。
map、filter、reduceを連結すると読みやすい場面もありますが、大量データでは中間配列が増えます。読みやすさを優先しつつ、負荷が気になる処理だけreduceなどで集約するとよいでしょう。こんなときどうする?トラブルシューティング
初心者がつまずきやすいのは、戻り値、途中終了、型変換、非同期です。これらはforEachとmapの仕様から起こるため、書く前にメソッドの役割を合わせるほうが安定すると整理できるのが一般的です。
forEachで値を返そうとしてしまう
forEachの戻り値は常にundefinedです。配列から条件に合う値を取り出したいなら、find、filter、someのように目的に合うメソッドを使います。
結果: 期待される出力は、wrongがundefined、foundがid 5のユーザーオブジェクトです。
この例では、return userがforEach全体の戻り値にならない点が原因です。条件に合う1件だけが必要ならfind、該当する複数件が必要ならfilterを選ぶと目的が合います。
mapの結果を使っていない
mapは新しい配列を作るメソッドなので、戻り値を捨てると処理意図が薄くなります。ログ出力や外部変数への追加だけなら、forEachを使うほうが読み手に伝わりやすい。
結果: 期待される出力は、forEach側で大文字文字列が個別に表示され、map側で大文字の配列が表示される形です。
そのため、コードレビューでは「戻り値を使っているか」を確認すると判断しやすくなります。戻り値が不要ならforEach、必要ならmapという単純な線引きが有効です。
文字列と数値の変換ミス
フォームやCSVから受け取った値は文字列になりやすく、+が数値加算ではなく文字列結合として働く場合があります。mapで数値配列へ変換するなら、Number()やparseInt()を明示すると理解できるのが現実的です。
結果: 期待される出力は、wrongが['11', '21', '31']、fixedが[2, 3, 4]です。
この問題はtypeofで中間値を確認すると原因を追いやすくなります。小数を含む値ならNumber()、整数だけを扱う入力なら基数を意識してparseInt(value, 10)を使う判断もあります。
デバッグと負荷の見直し
デバッグでは、変換前、変換中、変換後のどこで値が崩れたかを切り分けますが、覚えておくと役立つでしょう。console.table()、console.group()、debuggerを使うと処理順を確認しやすい。
ただし、ログを残したまま大量データを処理すると、ブラウザのコンソール表示が重くなることがあると整理できます。開発時だけdebugModeを有効にし、本番用コードでは不要なログを取り除く運用が一般的です。
document.writeのような古い出力方法に寄せず、textContent、append、テンプレート描画など、用途に合う現行の書き方を選びます。まとめ
forEachとmapの違いは、戻り値と副作用で判断できると覚えるとよいでしょう。forEachは各要素に処理を実行してundefinedを返し、mapは各要素の変換結果から新しい配列を返します。
そのため、DOMへの反映、イベント登録、ログ出力、既存データの更新はforEachが合いやすく、APIレスポンスの整形、表示用データ作成、条件付き変換、集計前の抽出はmapが扱いやすいと言えますが、これは押さえたい点です。途中終了ならfindやsome、集計ならreduceへ切り替えると目的に合いると考えられます。
これらを使い分けると、JavaScriptの配列操作は「反復」「変換」「探索」「集計」に分けて読めます。forEachとmapは、処理後に何が残るのかを基準に選ぶのが実用的。
関連記事
- JavaScriptのforEachでreturnを活用する6つのテクニック
- JavaScriptイベント徹底解説!30個の使い方と応用例
- JavaScriptにおけるイベントハンドラを完全ガイド!20選の実践サンプルコード付き
- JavaScriptで拡張子を活用する方法12選!初心者でも簡単にできる方法を紹介
- JavaScriptでカレンダーを作成!サンプルコード10選で簡単理解
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


