forEach で配列をまわす

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部

このレッスンで分かること

  • 配列.forEach((要素) => { 処理 }) で配列を 1 つずつ処理できます
  • コールバックは第 2 引数でインデックスも受け取れます
  • forEach は途中で break できません。中断が要るなら for-of を使います

forEach で配列をまわす とは

配列の各要素に対してコールバック関数を順番に呼んでくれるメソッドです。作品一覧の組み立てを forEach で書き直します。

ループとコールバックが合わさる

第5章で forfor-of を学び、前のレッスンでコールバックを学びました。この 2 つが合わさったものが forEach です。配列が自分で自分をまわしてくれて、要素ごとに渡した関数を呼んでくれます。

まずは for-of と並べてみましょう。山田 太郎さんの作品一覧を表示するコードです。

const works = ["プロフィールサイト", "自己紹介カード", "スキル一覧の表"]; // for-of for (const work of works) { console.log(work); } // forEach works.forEach((work) => { console.log(work); });

結果はまったく同じです。forEach は配列が持っているメソッドで、引数にコールバック関数を 1 つ受け取ります。配列の要素を先頭から順に取り出し、その要素を引数にしてコールバックを呼びます。ループの仕組みは forEach の側にあるので、こちらは「各要素に何をするか」だけを書きます。

forEach に渡しているのはアロー関数のコールバックです。前のレッスンで学んだ fn を渡す形が、そのままここで実用されています。

インデックスも受け取れる

コールバックは引数を最大 3 つ受け取れます。よく使うのは最初の 2 つです。

引数中身
第 1 引数要素そのもの
第 2 引数インデックス。0 から始まる
第 3 引数配列そのもの

番号付きの一覧を作ってみましょう。

const works = ["プロフィールサイト", "自己紹介カード", "スキル一覧の表"]; const lines = []; works.forEach((work, index) => { lines.push((index + 1) + ". " + work); }); console.log(lines.join("\n")); // 1. プロフィールサイト // 2. 自己紹介カード // 3. スキル一覧の表

必要な引数だけ書けばよく、インデックスが不要なら第 1 引数だけで構いません。第 3 引数の配列そのものは、入門段階ではほとんど使いません。

戻り値は undefined

forEach 自体の戻り値は常に undefined です。結果を集めたいときは、外側に配列を用意して push するか、return で値を集める別のメソッドを使います。

const works = ["プロフィールサイト", "自己紹介カード"]; const result = works.forEach((work) => work + " 完成"); console.log(result); // undefined

forEach は「各要素に何かする」ための道具であって、「各要素を変換した新しい配列を作る」道具ではありません。変換したいときに使う map、絞り込みたいときに使う filter、1 つの値にまとめたいときに使う reduce という仲間がいます。この 3 つは実践 JavaScript のコースで扱うので、いまは名前だけ覚えておいてください。

空の配列に forEach を呼んでもエラーにはならず、コールバックが 1 度も呼ばれずに終わります。要素数 0 を特別扱いする if は要りません。

for-of との使い分け

どちらも配列を 1 つずつまわす道具ですが、性格が違います。

観点for-offorEach
書き方構文配列のメソッド
途中で中断break できるできない
次の要素へ飛ばすcontinue できるreturn で代用
インデックスentries() などが要る第 2 引数で取れる
戻り値無しundefined
相性中断・スキップがある処理全要素に同じ処理

いちばん大事なのが中断できるかどうかです。forEach の中で break を書くと構文エラーになります。

// NG SyntaxError になる works.forEach((work) => { if (work === "自己紹介カード") break; console.log(work); });

forEach に渡しているのは関数なので、その中の break はループを抜ける文として成立しません。ループを止めているのは forEach の側であり、コールバックからは手が届かないのです。

途中で止めたいなら for-of を使います。

for (const work of works) { if (work === "自己紹介カード") break; console.log(work); }

一方、その要素だけ飛ばしたいだけなら forEach でも return で代用できます。コールバックが終わるだけで、次の要素の処理は続きます。

works.forEach((work) => { if (work === "自己紹介カード") return; // この要素だけ飛ばす console.log(work); });

この returncontinue に相当します。break の代わりにはならない、という点を取り違えないでください。

見つかった時点で探索を打ち切りたい場面は実務でよくあります。そういうときは for-of か、第7章で学ぶ find を使います。全件に同じ処理をするなら forEach が読みやすい、という住み分けです。

定番の型 lines に集めて join する

forEach で表示用の文字列を作るときは、次の 3 手順が定番になります。

  1. 空の配列を用意する
  2. forEach の中で push して行を足していく
  3. 最後に join で 1 本の文字列にする
function listWorks(works) { const lines = []; works.forEach((work, index) => { lines.push((index + 1) + ". " + work); }); return lines.join("\n"); } console.log(listWorks(["プロフィールサイト", "自己紹介カード"])); // 1. プロフィールサイト // 2. 自己紹介カード

lines は関数の中で宣言します。前のレッスンで学んだとおり、関数の外に置くと 2 回目に呼んだときに前回の行が残ります。

条件で行を飛ばしたいときは、push の前に return を書きます。連番を飛ばしたくないなら、index ではなく lines.length + 1 を番号に使うと、実際に追加した行数どおりの番号になります。

works.forEach((work) => { if (work === "") return; lines.push((lines.length + 1) + ". " + work); });

よくある間違い

1. forEach の戻り値を使おうとする

// NG 戻り値は undefined const titles = works.forEach((work) => work + " 完成"); // OK 外の配列に集める const titlesOk = []; works.forEach((work) => { titlesOk.push(work + " 完成"); });

2. break で抜けようとする

// NG 構文エラー works.forEach((work) => { if (work === "自己紹介カード") break; });

中断が必要になった時点で for-of に書き換えます。無理に forEach のまま解決しようとしないでください。

3. コールバックに丸括弧を付けて渡す

const show = (work) => console.log(work); // NG その場で 1 回だけ実行され、undefined が渡される works.forEach(show()); // OK 関数そのものを渡す works.forEach(show);

前のレッスンの fnfn() の区別が、そのままここでも効いてきます。

要件

  1. 配列の走査には forEach を使うこと
  2. 行を集める配列は関数の中で宣言すること
  3. 空文字列の要素は飛ばし、連番は実際に追加した行数どおりに振ること
  4. 表示できる作品が 0 件のときは文字列 作品はまだありません を返すこと

入出力例

listWorks(["プロフィールサイト","自己紹介カード","スキル一覧の表"]) → "1. プロフィールサイト 2. 自己紹介カード 3. スキル一覧の表" listWorks(["プロフィールサイト","","スキル一覧の表"]) → "1. プロフィールサイト 2. スキル一覧の表" listWorks(["自己紹介カード"])"1. 自己紹介カード" listWorks([])"作品はまだありません" listWorks(["",""])"作品はまだありません"

ヒント

main.js
main.js
学習モード

メモ

forEach で配列をまわす

⌘S で保存