はじめに
JavaScriptのforEachでreturnを使うと、現在のコールバック関数だけを抜けて次の要素へ進みます。breakのようにループ処理全体は止まらないため、途中終了が必要ならsome、every、find、通常のfor...ofを選びます。
forEachはログ出力、DOM更新、既存配列への追加など、副作用を伴う処理に向きますし、ここがポイントです。新しい配列ならmapやfilter、集約ならreduceが読みやすい場面も多いです。
- JavaScript: ECMAScript 2024相当
- Node.js: 22.0.0
- ブラウザ: Google Chrome 126
公式仕様に近い確認先として、配列の反復処理はMDNのArray.prototype.forEach()、新しい配列を返す処理はMDNのArray.prototype.map()が参考になります。非同期処理ではMDNのPromise.all()も確認しておくと判断しやすくなります。
結果: 期待される出力は1、2、4、5です。3の処理だけが飛ばされ、forEachのループ処理自体は続きますし、ここがポイントです。
forEach内でのreturnの基本
forEachのreturnはコールバック関数から戻るだけです。return falseでも全体は止まらず、次の要素で同じコールバック関数が呼ばれます。
特定の要素を処理対象から外すなら、条件に合わない値で早めにreturnするとネストを浅く保てます。途中で探索を止める用途ならfind、真偽判定ならsomeやevery、細かい制御ならforやfor...ofが合いるのが基本です。
returnで現在の要素だけをスキップする
偶数だけを出力したいときは、奇数でreturnするのが基本です。処理本体を深いifに入れずに済み、条件が増えても読みやすく保てます。
結果: 期待される出力は2、4、6です。奇数のときだけreturnで現在のコールバック関数を終え、偶数のときにconsole.logへ進みますが、これは押さえたい点です。
returnは値を返す目的ではなく、以降の処理を読ませない分岐です。forEachは戻り値を使わないため、return numやreturn trueも外側には渡りません。
returnでforEach全体は止まらない
returnを見つけた時点でループ処理が終わる、と考えると誤りです。制御対象は外側ではなく、各要素ごとのコールバック関数です。
結果: 期待される出力は1、2、3、4、5です。3でreturnしても、その後の4と5にも処理が回ります。
「条件に合う値が見つかったら終わり」ならforEachを避けます。値を探すならfind、存在判定だけならsomeが合いるのが目安です。
💡 Tips:forEach内のreturnは「その要素の残り処理を読ませない」ための書き方です。探索の途中終了、変換結果の生成、条件抽出を同時に担わせると意図がぼやけますし、ここがポイントです。
| 処理 | 主な用途 | 戻り値 | 途中終了 | 向く場面 |
|---|---|---|---|---|
forEach | 各要素への副作用 | undefined | 不可 | ログ、DOM更新、外部配列への追加 |
return | 現在の関数を抜ける | 関数次第 | forEach全体は不可 | 条件外の要素をスキップ |
for | 細かい反復制御 | なし | 可 | インデックス制御、逆順処理 |
for...of | 値を順番に処理 | なし | 可 | breakやcontinueを使う処理 |
map | 変換 | 新しい配列 | 不可 | 全要素を別の値へ変える |
filter | 抽出 | 新しい配列 | 不可 | 条件に合う値だけ残す |
reduce | 集約 | 任意の値 | 不可 | 合計、分類、オブジェクト化 |
some | いずれか判定 | boolean | 可 | 条件を満たす値の存在確認 |
every | 全件判定 | boolean | 可 | 全要素が条件を満たすか確認 |
find | 最初の一致取得 | 要素またはundefined | 可 | ID検索、条件一致の取得 |
findIndex | 最初の位置取得 | 数値 | 可 | 一致した位置を使う処理 |
Object.keys | キー配列化 | 配列 | 不可 | オブジェクトのキー巡回 |
Object.values | 値配列化 | 配列 | 不可 | 値だけを集計 |
Object.entries | キーと値の配列化 | 配列 | 不可 | キーと値を同時に扱う |
push | 末尾追加 | 配列長 | 対象外 | forEach内で結果配列へ追加 |
console.log | 確認出力 | undefined | 対象外 | 処理の流れを確認 |
try | 例外監視 | なし | 対象外 | 危険な処理を囲む |
catch | 例外処理 | なし | 対象外 | エラー時の復旧 |
throw | 例外発生 | なし | 可 | 不正値を明示する |
async | 非同期関数 | Promise | 対象外 | 非同期処理を関数化 |
await | Promise待機 | 解決値 | 対象外 | async関数内の順序制御 |
Promise.all | 並列待機 | 配列 | 拒否時に中断 | 複数の非同期処理を待つ |
setTimeout | 遅延処理 | タイマーID | 対象外 | 非同期の例示 |
typeof | 型確認 | 文字列 | 対象外 | 数値や文字列の判定 |
Number.isFinite | 有限数判定 | boolean | 対象外 | 数値入力の検査 |
Array.isArray | 配列判定 | boolean | 対象外 | 入力値の検査 |
includes | 包含判定 | boolean | 対象外 | 除外リストの確認 |
trim | 空白除去 | 文字列 | 対象外 | フォーム値の整形 |
toUpperCase | 大文字化 | 文字列 | 対象外 | 表示用文字列の加工 |
structuredClone | 深いコピー | 複製値 | 対象外 | 元データを壊さない加工 |
早見表の要点は、forEachが戻り値を組み立てる道具ではない点です。目的を副作用、変換、抽出、集約、探索に分けると、選ぶループ処理も決まります。
forEachと他のループメソッドとの比較
forEachと他の配列メソッドは、返り値と途中終了の可否で整理できます。アロー関数の見た目は似ても、returnの扱いはメソッドごとに違いるのがポイントです。
mapでは戻り値が新しい配列の要素になり、filterでは真偽値が採用可否を決めますが、これは押さえたい点です。forEachでは戻り値が捨てられるため、結果配列を作る目的では遠回りです。
forEachとfor文の違い
for文は初期化、条件、更新を自分で書くため、開始位置、終了条件、増分、逆順、途中終了を細かく扱えます。全件に同じ処理をするだけならforEachでも十分です。
結果: 期待される出力は、for文側がa、bで止まり、forEach側がa、b、dを出するのが一般的です。breakとreturnの違いが表れます。
途中で止めたい、偶数番目だけ処理したい、後ろから読むといった条件があるならfor文が扱いやすいです。
forEachとmapの違い
mapは新しい配列を返すため、変換の意図がコードに残ります。forEachで外側へpushするより、returnした値が結果になるmapのほうが伝わりやすいです。
結果: 期待される出力はいずれも[110.00000000000001, 220.00000000000003, 330]に近い配列です。小数の丸めは別問題として、変換目的ならmapのreturnが結果配列を作ります。
forEachは外側のwithTaxByForEachを変更しています。副作用が悪いわけではありませんが、変換なのか追加なのかを区別すると追いやすくなるのが現実的です。
someやfindで途中終了を表す
途中終了が必要な判定では、someとfindが自然な候補です。someはコールバック関数がtrueを返した時点で止まり、findは条件に合う最初の要素を返するのが目安です。
結果: 期待される出力はtrueと{ id: 2, active: true }です。探索の意図がsomeとfindに現れ、forEachでフラグ変数を管理する必要がありません。
変換ならmap、抽出ならfilter、合計や分類ならreduceを選ぶと、returnの意味がメソッド名と結びつきます。アロー関数の短い構文も、目的が明確なときに効きます。
forEachの戻り値は常にundefinedです。const result = array.forEach(...)の形で結果配列を受け取ろうとすると、意図と違う値になると整理できると整理できるのがポイントです。関連する配列メソッドは、内部記事のJavaScriptのforEach・mapの使い分けも参照できます。イベント処理では、JavaScriptイベントの使い方やイベントハンドラの実践例も関連します。
実践的なforEachの使用例
forEachで配列を巡回し、条件に合わない要素をreturnで飛ばしてから副作用を行う形はよく使われますが、これは押さえたい点です。ログ出力、DOM更新、既存の配列やオブジェクトへの反映では短く収まりますし、これが一つの目安です。
結果を新しく作る処理まで寄せると、mapやfilterより意図が弱くなります。forEachは副作用、returnはスキップ、mapは変換、filterは抽出と分けますし、これが一つの目安です。
配列の要素を条件で処理する
偶数だけを集める処理はfilterでも書けますが、既存の配列へ追加しながら別処理も行うならforEachも候補です。奇数で早めにreturnすると、処理本体を浅く保てます。
結果: 期待される出力は[2, 4, 6, 8]です。奇数の要素ではreturnによりpushへ進まず、偶数だけがevenNumbersへ追加されますが、覚えておくと役立つでしょう。
純粋な抽出だけなら、numbers.filter((num) => num % 2 === 0)のほうが短くなると理解できます。抽出と同時にログや別の状態更新がある場合はforEachも現実的です。
オブジェクトのプロパティを操作する
オブジェクト自体にはforEachがないため、Object.keys、Object.values、Object.entriesで配列化します。キーと値を使うならObject.entriesが読みやすいです。
結果: 期待される出力は{ name: 'SAKURA', age: 29, city: 'TOKYO', newsletter: true }です。文字列のプロパティだけがtoUpperCaseで変換されます。
この例は元のprofileを書き換えます。元データを保つならstructuredCloneや{ ...profile }で複製してから処理すると覚えるとよいでしょう。
フォーム入力の空文字を除外する
入力配列では、空文字や空白だけの値を除外する場面があるのが一般的です。trimで空になった値をreturnすれば、後続の加工を分けられます。
結果: 期待される出力は['javascript', 'foreach', 'return']です。空文字と空白だけの値はスキップされ、残ったタグだけが小文字化されますが、覚えておくと役立つでしょう。
normalizedのような中間変数を置くと、条件判定と追加処理の意味が分かれます。アロー関数を短くしすぎるより、意図が読める名前を優先します。
DOM要素の更新に使う
ブラウザでは、document.querySelectorAllが返すNodeListにもforEachを使える環境があると考えられますし、ここを基本と考えるとよいでしょう。要素ごとのclassList.addやtextContent更新は、副作用目的のforEachに合います。
結果: 期待される表示は、data-disabled="true"ではない.menu-itemにis-activeクラスが付く状態です。無効化された要素はreturnで処理を飛ばします。
複数要素へイベントを設定する場合はaddEventListenerと組み合わせますし、ここを基本と考えるとよいでしょう。関連する基礎はJavaScriptイベント徹底解説、実装例はJavaScriptにおけるイベントハンドラを完全ガイドが参考になるのが現実的です。
よくあるエラーと対処法
forEach周辺のエラーは、期待した制御フローとのズレから起きやすいです。returnで配列が作られる、非同期処理の完了を待つ、途中終了できる、という誤解が代表例です。
直すときは「戻り値が必要か」「全件処理か途中終了か」「非同期の順番を待つか」を分けます。追いにくい場合は開発者ツールでbreakpointを置き、call stackと変数の変化を確認すると言えるでしょう。
非同期処理で完了前に次へ進む
forEachのコールバック関数をasyncにしても、外側は各Promiseの完了を待ちません。awaitはasync関数内では働きますが、外側の流れは止めません。
結果: 期待される出力は、fetchValueの完了前なら[]になる可能性があります。forEachは非同期の完了を待たず、直後のconsole.logへ進むためです。
並列に処理してすべて待つなら、mapでPromise配列を作り、Promise.allに渡します。returnしたPromiseが配列に入り、完了後の結果をまとめて受け取れますし、ここがポイントです。
結果: 期待される出力は、fetchValueが解決した値を並べた配列です。mapのreturnがPromise配列を作り、Promise.allが完了を待ちますし、ここがポイントです。
forEachの戻り値を配列だと思う
forEachは常にundefinedを返します。アロー関数内でreturn num * 2を書いても、新しい配列は受け取れません。
結果: 期待される出力はundefinedです。returnした値はforEachの外側へ配列として集まりません。
変換結果が必要ならmapへ置き換えますが、これは押さえたい点です。mapではコールバック関数のreturnが新しい配列の各要素になります。
結果: 期待される出力は[2, 4, 6]です。変換を表す処理ではmapを使うと、戻り値の意味が明確になるのがポイントです。
途中終了したつもりで処理が続く
検索処理でforEachを使うと、一致後も最後までループ処理が続きますが、これは押さえたい点です。最初の一致だけが欲しいならfindのほうが素直です。
結果: 期待される出力は{ id: 'c', stock: 5 }です。bでreturnしても全体は止まらないため、後続のcで値が上書きされます。
findは条件に合う最初の要素を返し、条件が成立した時点で後続の確認を行いません。
結果: 期待される出力は{ id: 'b', stock: 3 }です。最初に条件を満たした要素を取得する目的なら、findが読みやすい選択になります。
引数の扱いを誤る
forEachのコールバック関数には、要素、インデックス、元配列の順に引数が渡されますし、これが一つの目安です。順番を間違えるとログや条件判定がずれますし、これが一つの目安です。
結果: 期待される出力は1/3: write、2/3: review、3/3: publishです。第1引数が要素、第2引数がインデックス、第3引数が元配列になります。
使わない引数まで書く必要はありません。forEach自身が渡すindexやarrayに、毎回デフォルト値を付ける必要も通常ありません。
forEachの構文だけでなく、戻り値を使うメソッドとの違いを同時に見ると理解が速くなるのが現実的です。新しい配列が欲しい処理にforEachを使っていないか確認しましょう。forEachを使ったアドバンストテクニック
発展的な使い方では、forEachだけに固執せず、filter、map、reduce、Object.entriesを組み合わせますが、覚えておくと役立つでしょう。目的ごとに分けると、returnの意味が混ざりません。
外部状態の更新やDOMの直接変更ではforEachが適します。ループ処理の目的を先に決め、アロー関数の短さより可読性を優先します。
複数の配列操作をチェーンする
都市で絞り込み、年齢を取り出し、合計する処理はfilter、map、reduceの連結で表せますし、ここを基本と考えるとよいでしょう。各段階の役割が見えやすくなると整理できます。
結果: 期待される出力は60です。Tokyoのメンバーだけを残し、年齢を配列化し、最後に合計しています。
forEachで書くと、条件判定と合計更新をひとつの関数に入れる形になります。条件や加工が増えるほど、チェーンで段階を分けたほうが追いやすくなるのが基本です。
条件分岐を関数に切り出す
複雑な条件分岐をforEach内へ直接書くと、if、else if、return、pushが混ざりますが、覚えておくと役立つでしょう。判定やメッセージ生成を関数へ分けると、巡回と追加に集中できます。
結果: 期待される出力は['Alice: standard news', 'Bob: upgrade guide', 'Carol: premium campaign']です。分岐のreturnはcreateMessageの戻り値として働きます。
forEach内のコールバック関数は短くなり、条件の追加や文言変更はcreateMessageに閉じます。巡回処理とビジネスルールを分けて考えられますし、ここがポイントです。
例外処理で不正データを飛ばす
不正値が混ざる可能性がある場合、tryとcatchで個別に扱えますし、ここを基本と考えるとよいでしょう。catch内でreturnすれば、その要素だけを止めて他は続けられます。
結果: 期待される出力は、エラー出力にvalue must be a finite number、通常出力に[20, 40, 60]です。不正な値だけを飛ばして処理を続けます。
入力値の検査だけならfilterで先に絞るほうが単純な場合もあります。通常の条件分岐で済むものはifやfilterで表するのが目安です。
Mapに集計する
カテゴリ別件数を数える処理では、MapとforEachを組み合わせると明確です。値を返すのではなく、集計用のMapを更新する副作用が目的です。
結果: 期待される出力は{ book: 2, tool: 1, food: 1 }です。Mapにカテゴリごとの件数を蓄積し、最後にObject.fromEntriesで確認しやすい形へ変換しています。
同じ集計はreduceでも書けます。集計結果を式として返すならreduce、既存状態を段階的に更新する意図ならforEachが合いるのがポイントです。
forEach内で配列自身を追加・削除すると、読み手が処理順を追いにくくなると言えるでしょう。入力配列と出力先を分ける、またはmapやfilterで新しい配列を作る設計を検討してください。ファイル名や拡張子を配列で扱う処理では、JavaScriptで拡張子を活用する方法のような文字列操作も組み合わせますし、ここがポイントです。日付配列やカレンダー表示では、JavaScriptでカレンダーを作成する例も関連領域になります。
まとめ
JavaScriptのforEachでreturnを使うと、現在のコールバック関数だけを終了し、次の要素のループ処理へ進みますが、これは押さえたい点です。途中終了したい場面ではfor、for...of、some、findを選びます。
forEachは副作用、mapは変換、filterは抽出、reduceは集約という役割があると理解できます。アロー関数で短く書けても、returnがどこへ渡るかを確認することが大切です。
配列操作の読みやすさはメソッド選びで変わりますし、これが一つの目安です。forEachに変換、抽出、探索、非同期待機をすべて任せず、目的に合う構文へ分けます。
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


