JavaScriptにおいて、データの集合を効率的に処理するための「繰り返し処理」は、プログラムの基礎でありながら、最も奥が深いテーマの一つです。
配列の操作、オブジェクトの走査、あるいは非同期処理の連続実行など、シチュエーションに応じて最適な構文を選択することは、コードの可読性と実行パフォーマンスを両立させるために不可欠です。
モダンなJavaScript開発(2026年現在)では、単にループを回すだけでなく、宣言的な記述や非同期イテレーションといった高度な手法も一般化しています。
本記事では、初心者から中級者のエンジニアに向けて、主要な繰り返し構文の使い分けから、現場で役立つ効率的な書き方までを詳しく解説します。
JavaScriptにおける繰り返し処理の重要性
JavaScriptでアプリケーションを構築する際、サーバーから取得したリストデータの表示や、複雑な計算アルゴリズムの実装など、同じ処理を何度も繰り返す場面が頻繁に登場します。
繰り返し処理を適切に記述できないと、コードが冗長になり、バグが混入しやすくなるだけでなく、アプリケーションの動作が重くなる原因にもなり得ます。
2020年代後半のJavaScriptエンジンは非常に高度に最適化されていますが、それでもなお、適切な構文を選択する知見は、保守性の高いコードを書くプロフェッショナルにとって必須のスキルと言えるでしょう。
基本の繰り返し構文:for文とwhile文
まずは、すべてのループ処理の基本となる伝統的な構文から見ていきましょう。
これらは柔軟性が高く、あらゆる繰り返し処理の基礎となります。
汎用性の高いfor文
for文は、繰り返す回数が決まっている場合に最もよく使われる構文です。
初期化、条件式、更新式の3つの要素で構成されます。
// 基本的なfor文の例
const limit = 5;
for (let i = 0; i < limit; i++) {
console.log(`現在のカウントは ${i} です`);
}
現在のカウントは 0 です
現在のカウントは 1 です
現在のカウントは 2 です
現在のカウントは 3 です
現在のカウントは 4 です
for文の強みは、ループの制御が完全に開発者の手にあることです。
例えば、インデックスを2ずつ増やしたり、特定の条件で逆順に回したりといった操作が容易です。
しかし、記述量が多くなりがちで、インデックスの管理ミス(オフバイワンエラーなど)を引き起こしやすいという側面もあります。
条件に応じたwhile文とdo…while文
回数ではなく、「特定の条件が満たされている間」処理を継続したい場合にはwhile文が適しています。
let energy = 100;
let distance = 0;
while (energy > 0) {
distance += 10;
energy -= 25; // 1回ごとにエネルギーを消費
console.log(`走行距離: ${distance}km, 残りエネルギー: ${energy}`);
}
走行距離: 10km, 残りエネルギー: 75
走行距離: 20km, 残りエネルギー: 50
走行距離: 30km, 残りエネルギー: 25
走行距離: 40km, 残りエネルギー: 0
while文を使用する際の注意点は、無限ループの回避です。
終了条件がいつか必ず満たされるように設計しなければ、ブラウザのタブがフリーズする原因になります。
また、最低でも一度は必ず処理を実行したい場合には、do...while文を使用します。
let count = 0;
do {
console.log("この処理は必ず1回は実行されます");
count++;
} while (count < 0); // 条件は最初から偽
この処理は必ず1回は実行されます
配列とオブジェクトの反復処理
現代のJavaScript開発では、生のfor文よりも、配列やオブジェクトに特化した反復構文が好まれます。
for…of:配列やイテラブルの走査
ES6(ECMAScript 2015)で導入されたfor...of文は、配列の要素を直接取り出して処理するのに最適です。
const fruits = ["りんご", "バナナ", "オレンジ"];
for (const fruit of fruits) {
console.log(`${fruit}を食べます`);
}
りんごを食べます
バナナを食べます
オレンジを食べます
for...ofは、配列だけでなく、Map、Set、文字列、NodeListといったイテラブル(反復可能)なオブジェクト全般に使用できます。
インデックスを意識する必要がないため、コードが非常にクリーンになります。
for…in:オブジェクトのプロパティ走査
オブジェクトのキーをループ処理したい場合にはfor...inを使用しますが、ここには注意が必要です。
const user = {
name: "田中",
age: 28,
role: "エンジニア"
};
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
name: 田中
age: 28
role: エンジニア
重要:for…in文は、継承されたプロトタイプチェーン上のプロパティも列挙してしまう可能性があります。そのため、純粋にオブジェクト自身のプロパティだけを処理したい場合は、Object.keys() や Object.entries() を for...of と組み合わせて使う手法が2026年現在のスタンダードです。
// 推奨されるオブジェクトのループ手法
for (const [key, value] of Object.entries(user)) {
console.log(`${key}は${value}です`);
}
配列の高階関数による宣言的な繰り返し
JavaScriptの配列には、ループ処理を抽象化した強力なメソッドが備わっています。
これらを使うことで、「どのように繰り返すか(手続き)」ではなく「何をしたいか(目的)」を明示する宣言的なコードが書けます。
forEach:単純な実行
副作用(ログ出力やDOM操作など)を伴うループにはforEachが使われます。
const tags = ["JavaScript", "TypeScript", "React"];
tags.forEach((tag, index) => {
console.log(`${index + 1}番目のタグは ${tag} です`);
});
1番目のタグは JavaScript です
2番目のタグは TypeScript です
3番目のタグは React です
ただし、forEach内ではbreakやcontinueが使えないという制約があるため、途中でループを抜けたい場合はfor...ofやsome()を検討してください。
map:新しい配列の生成
各要素を加工して新しい配列を作りたい場合は、mapが最適です。
const prices = [100, 200, 300];
const taxRate = 1.1;
const inclusivePrices = prices.map(price => Math.floor(price * taxRate));
console.log(inclusivePrices);
[110, 220, 330]
filter:条件に合う要素の抽出
条件に合致する要素だけを抜き出すにはfilterを使用します。
const scores = [45, 80, 62, 95, 30];
const passingScores = scores.filter(score => score >= 60);
console.log(passingScores);
[80, 62, 95]
reduce:データの集計
配列を一つの値(合計値やオブジェクトなど)にまとめたい場合はreduceが強力です。
const items = [
{ name: "ノート", price: 150 },
{ name: "ペン", price: 100 },
{ name: "消しゴム", price: 80 }
];
const totalPrice = items.reduce((sum, item) => sum + item.price, 0);
console.log(`合計金額: ${totalPrice}円`);
合計金額: 330円
繰り返し処理の制御:breakとcontinue
ループの途中で処理を中断したり、特定の回だけスキップしたりするための制御構文について解説します。
break:ループの即時終了
特定の条件を満たした時点でループを完全に終わらせたい時に使用します。
const numbers = [1, 2, 3, 4, 5, 6, 7];
for (const num of numbers) {
if (num === 4) {
console.log("4が見つかったので終了します");
break;
}
console.log(num);
}
1
2
3
4が見つかったので終了します
continue:現在の反復をスキップ
特定の条件の時だけ処理を飛ばし、次のループへ進みたい時に使用します。
for (let i = 1; i <= 5; i++) {
if (i % 2 === 0) {
continue; // 偶数の時はログを出さない
}
console.log(`${i} は奇数です`);
}
1 は奇数です
3 は奇数です
5 は奇数です
構文の選び方とパフォーマンスの比較
どの繰り返し構文を使うべきか迷った際、以下の表を参考にしてください。
| 構文 | 主な用途 | 特徴 | 制御(break/continue) |
|---|---|---|---|
for | 汎用、回数指定 | 最速、自由度が高いが記述が冗長 | 可能 |
for...of | 配列・イテラブルの走査 | 読みやすく、標準的 | 可能 |
forEach | 配列への作用 | 関数型、宣言的 | 不可 |
map | 配列の変換 | 新しい配列を返す | 不可 |
while | 条件による継続 | 終了条件が動的な場合に最適 | 可能 |
2026年現在のパフォーマンス事情
かつては「for文が圧倒的に速く、forEachなどのメソッドは遅い」と言われていた時期もありました。
しかし、現在の主要ブラウザ(Chrome, Edge, Safari, Firefox)に搭載されているJavaScriptエンジンは、配列メソッドを強力に最適化しています。
したがって、数万件程度のデータであれば、速度の差は無視できるレベルです。
パフォーマンスを優先して読みづらいfor文を書くよりも、意図が伝わりやすい map や filter を優先して使うべきです。
ただし、数百万件を超える大規模なデータセットを扱う場合や、メモリ使用量を極限まで抑えたい組み込み環境などでは、伝統的なfor文が優位になることがあります。
応用:非同期処理の繰り返し
現代のJavaScript開発において避けて通れないのが、APIリクエストなどの非同期処理を伴うループです。
非同期ループの落とし穴
forEachの中でawaitを使っても、期待通りに待機してくれないという有名な問題があります。
// 期待通りに動かない例
const ids = [1, 2, 3];
ids.forEach(async (id) => {
await someAsyncFunction(id); // これが完了するのを待たずにforEach自体は終わる
});
console.log("すべて完了?"); // まだ終わっていないのに出力される
for await…of の活用
非同期イテラブルを順次処理するためには、for await...of構文を使用します。
async function processSequentially(items) {
for (const item of items) {
const result = await fetchItemData(item);
console.log(result);
}
console.log("すべての非同期処理が完了しました");
}
この書き方であれば、一つ一つの非同期処理が完了するのを待ってから次のループに進みます。
もし並列で一気に実行したい場合は、Promise.all()とmap()を組み合わせるのが定石です。
効率的な書き方のためのベストプラクティス
より高品質なコードを書くための、2026年流のテクニックを紹介します。
ネストを避ける
ループの中にさらにループがある「二重ループ」は、計算量が O(n^2) になり、パフォーマンス劣化の最大の原因となります。
Mapオブジェクトを活用して検索を O(1) に落とし込むなどの工夫ができないか検討しましょう。
早期リターンとガード節
ループ内の処理が複雑になる場合は、continueを使って処理の対象外を先に弾く(ガード節)ことで、インデントが深くならないようにします。
// 読みやすい書き方
for (const user of users) {
if (!user.isActive) continue; // アクティブでないユーザーはスキップ
if (user.age < 18) continue; // 未成年はスキップ
// メインの処理
sendNotification(user);
}
イミュータブル(不変性)の意識
元の配列を破壊せずに処理を行うことも重要です。
例えば、sort() や reverse() は元の配列を書き換えてしまいます。
2023年に導入された toSorted() や toReversed() を使うことで、安全に繰り返し処理に組み込むことができます。
まとめ
JavaScriptの繰り返し処理は、言語の進化とともに「命令的な記述」から「宣言的な記述」へとシフトしてきました。
- 単純な反復や、途中で抜け出したい場合は
for...of - データの変換や抽出には
map,filter - 特殊な条件下での反復には
while - 非同期データの順次処理には
for await...of
これらを適切に使い分けることが、プロフェッショナルなJavaScriptエンジニアへの第一歩です。
2026年の開発現場では、単に動くコードではなく、他人が読んで意図がすぐに理解できるコードがこれまで以上に重視されています。
本記事で紹介した各構文の特徴を理解し、プロジェクトに最適な手法を選択してください。
繰り返し処理のマスターは、JavaScript全体のスキルアップに直結します。
ぜひ、実際のコードを書きながらその挙動を体感してみてください。
