JavaScriptで繰り返し処理を行う際、「each」や「forEach」といった構文に戸惑う方は少なくありません。本記事では、forEachを中心に、for文やfor of、for inなどのループ構文との違いや使い分け方を丁寧に解説します。
目次
1.JavaScriptにおけるeachとは?
JavaScriptには「each」という文法は存在せず、これはjQuery特有の表現であり、現在はforEachなどのループ構文が主に使用されています。
jQueryを使った経験がある人や古い記事に触れた学習者が、現代のJavaScriptで似た処理を実現しようとした際に「each javascript」で参考になる情報を探した経験があるのではないでしょうか。しかし、JavaScriptでは「each」という構文や関数は存在しておらず、Array.prototype.forEach()がその代替として広く使用されています。
2.JavaScriptのforEach文の基本と構文解説
JavaScriptで配列を操作する際に、最もよく使われるメソッドの1つがforEachです。この章ではforEachの基本的な構文や使い方をはじめ、アロー関数との併用方法、従来のfunction式との違いについて解説します。
基本構文と使い方
forEachは、JavaScriptで配列を1つずつ処理するための基本的な繰り返しメソッドです。
このメソッドは配列の各要素に対して1回ずつ処理を実行できるよう設計されており、処理の順序が保証され、コードの可読性も高まります。
例えば、以下のコードでは配列内のフルーツ名を順番に出力しています。
const fruits = ["apple", "banana", "cherry"]; fruits.forEach(function(fruit, index) { console.log(`${index + 1}: ${fruit}`); }); |
このように、forEachは配列の内容に対して順番通りに処理を適用することができます。
アロー関数でより簡潔に
アロー関数とforEachを組み合わせることで、より短く読みやすいコードを書くことができます。
アロー関数は関数の構文を簡略化できるだけでなく、thisの取り扱いが直感的なため、ループ内の処理がすっきりします。
以下のように記述すると、従来のfunction式よりもシンプルな構文になります。
fruits.forEach((fruit, index) => { console.log(`${index + 1}: ${fruit}`); }); |
この形式は、関数が一行で完結する処理や、コールバック関数に最適です。
コードを簡潔に保ちたい場合は、アロー関数を活用したforEachの記述を習得しておくと良いでしょう。
function式とアロー関数の違い(thisの扱い)
function式とアロー関数では、thisの扱いが異なるため、処理の内容によって適切に使い分ける必要があります。
function式では呼び出し元によってthisが変化しますが、アロー関数では外側のスコープを継承するため、想定外の動作を避けることができます。
以下のコードは、function式を使った場合にthisがグローバルを参照してしまう例です。
const obj = { items: [1, 2, 3], logItems: function() { this.items.forEach(function(item) { console.log(this); // グローバルオブジェクト }); } }; |
一方、アロー関数を使うと次のように意図通りの挙動になります。
const objFixed = { items: [1, 2, 3], logItems: function() { this.items.forEach((item) => { console.log(this); // objFixed }); } }; |
ループ内でthisを正しく扱いたい場面では、function式とアロー関数の違いを理解して使い分けることが重要です。
関連記事
JavaScript配列完全ガイド|初期化・追加・操作から配列操作・連想配列まで徹底解説
JavaScriptの使い方【入門】基本構文や簡単プログラム例を初心者向けに解説
3.JavaScriptの他の繰り返し文との比較
JavaScriptではforEach以外にも複数の繰り返し構文が用意されており、用途や処理対象によって使い分けることが重要です。この章ではfor文・for in文・for of文・while文などの繰り返し文について、構文の特徴やforEachとの違いを解説します。
for文との比較
for文は、繰り返し回数やインデックスの制御が必要な場合に最適な構文です。
forEachではループの途中で処理を中断できないのに対し、for文ではbreakやcontinueを使って自由にフローを制御することができます。また、インデックスを細かく操作したい場合にも有効です。
for (let i = 0; i < 10; i++) { if (i === 5) break; console.log(i); } |
このように、特定の条件でループを終了したい場合に柔軟に対応できます。制御の柔軟性を重視したい場合や、ループ回数が明確なときは、for文が適しています。
for of文との比較
for of文は、配列や文字列など反復可能(イテラブル)なオブジェクトを扱う際に便利な構文です。
forEachと同様にシンプルで読みやすい一方で、breakやcontinueなどの制御文を使えるため、柔軟性も兼ね備えています。
const fruits = ["apple", "banana", "cherry"]; for (const fruit of fruits) { if (fruit === "banana") continue; console.log(fruit); } |
このように、for ofは配列をループ処理しながら条件分岐にも対応できます。配列を対象にしたループで、かつ処理の中断やスキップが必要な場合には、for ofの利用が適しています。
for in文との比較
for in文は、オブジェクトのプロパティ名(キー)を列挙したいときに使用します。JavaScriptでは、オブジェクトが配列とは異なる構造を持っているため、キー単位でループを行う必要があります。
const user = { name: "Alice", age: 30 }; for (const key in user) { console.log(`${key}: ${user[key]}`); } |
ただし、継承されたプロパティも対象になるため、hasOwnProperty()を使ったフィルタリングが必要な場面もあります。オブジェクトの各プロパティを走査する場合にはfor inが有効ですが、使用時には注意点もあるため適切に扱いましょう。
while文・do while文との比較
while文やdo while文は、明確な反復回数がない場合や、条件によって繰り返しを制御したいときに適しています。これらの構文は、繰り返しの前後に条件評価を挟むため、条件が満たされている間だけ処理を続ける柔軟な制御が可能です。
let count = 0; while (count < 3) { console.log(count); count++; } |
また、do while文では必ず1回は処理が実行されます。条件に基づいて処理の繰り返しを制御したい場合には、whileやdo whileを検討すると良いでしょう。
関連記事
JavaScriptのlengthプロパティ|配列・文字列の操作と取得できないときの対処法を解説
【初心者向け】JavaScript入門完全ガイド|基本構文や勉強方法(入門本や学習サイト)など解説
4.JavaScript|forEachが使えないケースとその理由
便利なforEachですが、すべての場面において万能というわけではありません。ループの中断や非同期処理との組み合わせなど、一部のケースではforEachが適さないことがあります。この章では、forEachの制約を整理し、それぞれに対する代替策を紹介します。
breakやcontinueが使えない
forEachではbreakやcontinueを使ってループを中断・スキップすることができません。forEachは、配列のすべての要素に対して順に処理を実行することを前提に設計されており、途中でループを止める制御構文(break/continue)には対応していません。
以下のコードは意図通りには動作しません。
[1, 2, 3, 4, 5].forEach(num => { if (num === 3) break; // SyntaxError: Illegal break statement console.log(num); }); |
このようなケースでは、for文やfor of文を使うことで、中断処理が可能になります。
for (const num of [1, 2, 3, 4, 5]) { if (num === 3) break; console.log(num); } |
ループの途中で処理を中断したい場合は、forEachではなくforやfor ofの使用を検討すべきでしょう。
returnではループを終了できない
forEach内でのreturnはループ全体を終了させることはできません。
returnはあくまで関数の終了を意味するためforEachのコールバック関数内で使用しても、次のループには影響を与えず、単にその1回の処理を抜けるだけです。
以下のように記述しても、ループ自体は継続します。
[1, 2, 3, 4, 5].forEach(num => { if (num === 3) return; console.log(num); // 1, 2, 4, 5 を出力(3はスキップ) }); |
これは「スキップ」には使えますが、「ループの終了」には不向きです。ループ全体の中断や明示的な終了が必要な処理には、forEachでは不十分であり、forやfor ofを活用する必要があります。
非同期処理との相性が悪い
forEachはasync/awaitとの相性が悪く、意図した順序やタイミングで非同期処理が実行されないことがあります。forEachは非同期関数を待たずに次のイテレーションを進めるため、処理の順序が崩れたり、完了前に次の処理が始まるリスクがあります。
以下のように記述しても、awaitは機能せず、非同期処理が並行して走ります。
const asyncTask = async (value) => { await new Promise(resolve => setTimeout(resolve, 1000)); console.log(value); };
await asyncTask(value); }); |
この場合は、順序を保証するにはfor ofを使用するのが安全です。
for (const value of [1, 2, 3]) { await asyncTask(value); } |
awaitによる逐次処理を必要とする場面では、forEachは避け、for ofでのループが適切です。
関連記事
JavaScript初心者向け【サンプルコード付】基礎から学習するための方法を解説
5.JavaScript|オブジェクトや連想配列をforEachで扱うには
forEachは配列に特化したメソッドであるため、オブジェクト(連想配列的な構造)に対して直接使うことはできません。しかし、Object.keys()やObject.entries()などのメソッドを組み合わせることで、オブジェクトにも同様の繰り返し処理を適用することが可能です。この章では、オブジェクト操作におけるforEachの実用的な使い方を解説します。
オブジェクトにforEachが使えない理由
JavaScriptのforEachは配列専用のメソッドであり、オブジェクトには直接使用できません。オブジェクトは配列とは異なる構造を持ち、Array.prototype.forEachの対象である「イテラブル」ではないためです。そのため、オブジェクトにforEachを適用しようとするとエラーになります。
const user = { name: "Taro", age: 28 }; // user.forEach(...) は実行できない(TypeError) |
このように、オブジェクトは配列のように直接ループ処理を適用できないのが特徴です。オブジェクトに対してforEachを使いたい場合は、まずキーやエントリを配列化する必要があります。
Object.keysやObject.entriesとの併用
Object.keys()やObject.entries()を使えば、オブジェクトのプロパティを配列化してforEachで処理できます。これらのメソッドは、オブジェクトのキーやキーと値のペアを配列として取得できるため、forEachとの併用が可能になります。
const user = { name: "Taro", age: 28 };
Object.keys(user).forEach(key => { console.log(`${key}: ${user[key]}`); });
Object.entries(user).forEach(([key, value]) => { console.log(`${key}: ${value}`); }); |
このようにして、オブジェクトのプロパティを配列と同様に処理できます。オブジェクトをforEachで処理したい場合は、Object.keys()やObject.entries()を活用するのが標準的な方法です。
for inとの使い分け
オブジェクトを処理する場合は、forEach+Object.keysのほか、for inも選択肢となります。ただし注意点もあります。for inはオブジェクトのすべての列挙可能なプロパティを対象としますが、プロトタイプチェーン上のプロパティも含まれてしまう可能性があるため、意図しない結果になることもあります。
const user = { name: "Taro", age: 28 }; for (const key in user) { if (user.hasOwnProperty(key)) { console.log(`${key}: ${user[key]}`); } } |
このようにhasOwnProperty()を用いることで、自分自身のプロパティに限定して処理できます。オブジェクトのプロパティを繰り返し処理するには、Object.entries()+forEachのほうが安全かつシンプルなケースが多いため、用途に応じて選び分けることが重要です。
6.まとめ
JavaScriptにおける繰り返し処理は多様であり、目的や対象によって最適な構文を選ぶことが重要です。配列処理に特化したforEachは、コードを簡潔に保ちながら効率よくループを実装できますが、中断や非同期処理には適さないという制約もあります。
本記事では、それぞれの構文の特性や使い分けを具体例とともに解説しました。繰り返し処理を正しく選択できるようになることで、より堅牢で読みやすいコードが実現できるでしょう。
本記事が皆様にとって少しでもお役に立てますと幸いです。
「フリーランスボード」は、数多くのフリーランスエージェントが掲載するITフリーランスエンジニア・ITフリーランス向けの案件・求人を一括検索できるサイトです。
開発環境、職種、単価、稼働形態、稼働日数など様々な条件から、あなたに最適なフリーランス案件・求人を簡単に見つけることができます。
単価アップを目指す方や、自分の得意なスキルを活かせる案件に参画したい方は、ぜひ「フリーランスボード」をご利用ください。
自身に最適なフリーランスエージェントを探したい方はこちらよりご確認いただけます。