はじめに#
プログラミングにおいて、同じ処理を繰り返し実行することは非常に重要です。JavaScriptでは、繰り返し処理(ループ)を実現するためにfor文やwhile文など複数の構文が用意されています。
本記事では、以下の内容を初心者向けにわかりやすく解説します。
- for文の基本構文: カウンタ変数を使った反復処理
- while文の基本構文: 条件が真の間繰り返す処理
- do…while文: 最低1回は実行されるループ
- for文とwhile文の使い分け: どちらを選ぶべきかの判断基準
- break・continueの使い方: ループの制御方法
- 無限ループの回避策: 初心者が陥りやすいミスとその対策
for文の基本#
for文は、繰り返し回数があらかじめ決まっている場合に使用する構文です。カウンタ変数を使って、指定した回数だけ処理を繰り返します。
基本構文#
1
2
3
|
for (初期化式; 条件式; 更新式) {
// 繰り返し実行される処理
}
|
各部分の役割は以下のとおりです。
| 部分 |
説明 |
| 初期化式 |
ループ開始前に1回だけ実行される(カウンタ変数の初期化) |
| 条件式 |
各反復の前に評価され、trueならループを継続 |
| 更新式 |
各反復の後に実行される(カウンタ変数の更新) |
基本的な例#
0から4までの数値を出力する例です。
1
2
3
4
5
6
7
8
9
|
for (let i = 0; i < 5; i++) {
console.log(i);
}
// 出力:
// 0
// 1
// 2
// 3
// 4
|
このコードの動作を詳しく見てみましょう。
flowchart TD
A[開始] --> B["初期化: let i = 0"]
B --> C{"条件判定: i < 5 ?"}
C -->|true| D["処理実行: console.log(i)"]
D --> E["更新: i++"]
E --> C
C -->|false| F[終了]
let i = 0でカウンタ変数iを0に初期化
i < 5がtrueなのでループ内の処理を実行
console.log(i)で現在のiの値を出力
i++でiを1増やす
- 2〜4を
i < 5がfalseになるまで繰り返す
カウントダウンの例#
for文は減算方向にも使えます。
1
2
3
4
5
6
7
8
9
|
for (let i = 5; i > 0; i--) {
console.log(i);
}
// 出力:
// 5
// 4
// 3
// 2
// 1
|
配列の要素を順番に処理する#
for文は配列の要素を順番に処理する際によく使われます。
1
2
3
4
5
6
7
8
9
|
const fruits = ["りんご", "みかん", "バナナ"];
for (let i = 0; i < fruits.length; i++) {
console.log(`${i + 1}番目: ${fruits[i]}`);
}
// 出力:
// 1番目: りんご
// 2番目: みかん
// 3番目: バナナ
|
配列のlengthプロパティを条件式に使うことで、配列の要素数分だけループを実行できます。
ネストしたfor文(多重ループ)#
for文の中にfor文を入れることで、二重ループを作成できます。九九の表を作成する例を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
for (let i = 1; i <= 3; i++) {
for (let j = 1; j <= 3; j++) {
console.log(`${i} × ${j} = ${i * j}`);
}
}
// 出力:
// 1 × 1 = 1
// 1 × 2 = 2
// 1 × 3 = 3
// 2 × 1 = 2
// 2 × 2 = 4
// 2 × 3 = 6
// 3 × 1 = 3
// 3 × 2 = 6
// 3 × 3 = 9
|
外側のループが1回実行されるごとに、内側のループが最初から最後まで実行されます。
while文の基本#
while文は、条件式がtrueである限り処理を繰り返す構文です。繰り返し回数が事前にわからない場合に適しています。
基本構文#
1
2
3
|
while (条件式) {
// 条件が true の間、繰り返し実行される処理
}
|
基本的な例#
1
2
3
4
5
6
7
8
9
10
11
12
|
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// 出力:
// 0
// 1
// 2
// 3
// 4
|
この例は先ほどのfor文と同じ結果を出力しますが、カウンタ変数の宣言・更新を別々に記述しています。
while文の動作フロー#
flowchart TD
A[開始] --> B{"条件判定"}
B -->|true| C["処理実行"]
C --> B
B -->|false| D[終了]while文は条件を先に評価するため、条件が最初からfalseの場合は一度も処理が実行されません。
1
2
3
4
5
6
7
|
let count = 10;
while (count < 5) {
console.log(count);
count++;
}
// 何も出力されない(条件が最初からfalseのため)
|
実践的な例:ユーザー入力の検証#
while文は、条件が満たされるまで処理を繰り返す場面で効果的です。以下は、有効な値が入力されるまで繰り返す疑似コードです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
let input = "";
let attempts = 0;
const maxAttempts = 3;
// 実際のアプリケーションでは prompt() や DOM操作で入力を受け取る
const simulatedInputs = ["", "invalid", "valid"];
while (input !== "valid" && attempts < maxAttempts) {
input = simulatedInputs[attempts];
console.log(`試行 ${attempts + 1}: "${input}"`);
attempts++;
}
if (input === "valid") {
console.log("有効な入力を受け取りました");
} else {
console.log("最大試行回数に達しました");
}
// 出力:
// 試行 1: ""
// 試行 2: "invalid"
// 試行 3: "valid"
// 有効な入力を受け取りました
|
do…while文#
do...while文は、条件を後で評価するため、最低1回は必ず処理が実行されます。
基本構文#
1
2
3
|
do {
// 最低1回は実行される処理
} while (条件式);
|
基本的な例#
1
2
3
4
5
6
7
8
9
10
11
12
|
let count = 0;
do {
console.log(count);
count++;
} while (count < 5);
// 出力:
// 0
// 1
// 2
// 3
// 4
|
while文との違い#
条件が最初からfalseの場合でも、do...while文は1回実行されます。
1
2
3
4
5
6
7
8
|
let count = 10;
do {
console.log(count);
count++;
} while (count < 5);
// 出力:
// 10(1回は実行される)
|
この違いを図で確認しましょう。
flowchart LR
subgraph while文
A1["条件判定"] --> B1["処理実行"]
B1 --> A1
end
subgraph do...while文
A2["処理実行"] --> B2["条件判定"]
B2 --> A2
end使用場面#
do...while文は、メニュー表示のように「最低1回は処理を実行し、その後条件によって継続するかを判断する」場面で役立ちます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
let selection;
const menu = ["1: 新規作成", "2: 編集", "3: 削除", "0: 終了"];
let iteration = 0;
const selections = [1, 2, 0]; // シミュレーション用
do {
console.log("=== メニュー ===");
menu.forEach((item) => console.log(item));
selection = selections[iteration];
console.log(`選択: ${selection}`);
iteration++;
} while (selection !== 0 && iteration < selections.length);
console.log("プログラムを終了します");
|
for文とwhile文の使い分け#
for文とwhile文はどちらも繰り返し処理を実現できますが、それぞれに適した場面があります。
使い分けの判断基準#
| 条件 |
推奨するループ |
理由 |
| 繰り返し回数が明確 |
for文 |
カウンタ変数の管理が一箇所にまとまる |
| 配列やリストの反復 |
for文、for…of |
インデックスやイテレータが活用できる |
| 終了条件が動的に変化 |
while文 |
条件式のみに集中できる |
| 最低1回は実行したい |
do…while文 |
条件判定前に処理が実行される |
| 無限ループ的な処理 |
while (true) |
明示的にbreakで抜ける設計に適する |
具体例で比較#
同じ処理をfor文とwhile文で書いた場合の比較です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// for文: 1から10までの合計
let sumFor = 0;
for (let i = 1; i <= 10; i++) {
sumFor += i;
}
console.log(sumFor); // 55
// while文: 1から10までの合計
let sumWhile = 0;
let j = 1;
while (j <= 10) {
sumWhile += j;
j++;
}
console.log(sumWhile); // 55
|
繰り返し回数が明確な場合(1から10まで)は、for文の方がカウンタ変数の管理がまとまっていて読みやすいです。
一方、以下のような「条件が満たされるまで」の処理ではwhile文が適しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// ランダムな値が5以上になるまで繰り返す
let randomValue;
let count = 0;
// 乱数のシミュレーション
const randomValues = [2, 1, 4, 3, 7];
while ((randomValue = randomValues[count]) < 5) {
console.log(`値: ${randomValue}(5未満なので継続)`);
count++;
}
console.log(`終了: ${randomValue}(5以上)`);
// 出力:
// 値: 2(5未満なので継続)
// 値: 1(5未満なので継続)
// 値: 4(5未満なので継続)
// 値: 3(5未満なので継続)
// 終了: 7(5以上)
|
break文とcontinue文によるループ制御#
ループの途中で処理を中断したり、特定の反復をスキップしたりするために、break文とcontinue文を使用します。
break文#
break文を使うと、ループを即座に終了できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
for (let i = 0; i < 10; i++) {
if (i === 5) {
console.log("5に達したのでループを終了");
break;
}
console.log(i);
}
// 出力:
// 0
// 1
// 2
// 3
// 4
// 5に達したのでループを終了
|
continue文#
continue文を使うと、現在の反復をスキップして次の反復に進みます。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
for (let i = 0; i < 5; i++) {
if (i === 2) {
console.log("2はスキップ");
continue;
}
console.log(i);
}
// 出力:
// 0
// 1
// 2はスキップ
// 3
// 4
|
実践的な例:特定条件での検索#
配列から特定の要素を検索し、見つかったらループを終了する例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const users = [
{ id: 1, name: "田中" },
{ id: 2, name: "鈴木" },
{ id: 3, name: "佐藤" },
{ id: 4, name: "高橋" },
];
let foundUser = null;
for (let i = 0; i < users.length; i++) {
if (users[i].id === 3) {
foundUser = users[i];
break; // 見つかったらループを終了
}
}
console.log(foundUser); // { id: 3, name: "佐藤" }
|
ネストしたループでのbreak#
多重ループで外側のループも終了させたい場合は、ラベルを使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
outerLoop: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
console.log(`i=${i}, j=${j}`);
if (i === 1 && j === 1) {
console.log("外側のループを終了");
break outerLoop;
}
}
}
// 出力:
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// i=1, j=1
// 外側のループを終了
|
無限ループとその回避策#
無限ループは、終了条件が満たされないために永遠に実行され続けるループです。意図しない無限ループはプログラムをフリーズさせる原因となります。
無限ループの例と問題点#
1
2
3
4
5
6
|
// 危険: 無限ループになる例(実行しないでください)
// let i = 0;
// while (i < 10) {
// console.log(i);
// // i++ を忘れている!
// }
|
この例では、i++を記述し忘れているため、iは常に0のまま条件i < 10が永遠にtrueとなります。
無限ループを避けるためのチェックリスト#
以下のポイントを確認することで、無限ループを防げます。
- カウンタ変数の更新を忘れていないか
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 悪い例
let i = 0;
while (i < 5) {
console.log(i);
// i++ がない!
}
// 良い例
let j = 0;
while (j < 5) {
console.log(j);
j++; // 必ず更新する
}
|
- 条件式が最終的にfalseになるか
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 悪い例: 条件が常にtrue
// while (true) {
// console.log("永遠に実行される");
// }
// 良い例: 明示的な終了条件
let running = true;
let counter = 0;
while (running) {
console.log(counter);
counter++;
if (counter >= 5) {
running = false; // 終了条件を設定
}
}
|
- 安全装置としての最大反復回数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
const MAX_ITERATIONS = 1000;
let iterations = 0;
let condition = true;
while (condition && iterations < MAX_ITERATIONS) {
// 何らかの処理
iterations++;
// 本来の終了条件
if (iterations === 10) {
condition = false;
}
}
if (iterations >= MAX_ITERATIONS) {
console.error("最大反復回数に達しました");
}
|
その他の繰り返し構文#
JavaScriptにはfor文とwhile文以外にも便利な繰り返し構文があります。ここでは概要を紹介します。
for…of文#
配列やイテラブルオブジェクトの要素を順番に取り出すための構文です。
1
2
3
4
5
6
7
8
9
|
const colors = ["赤", "青", "緑"];
for (const color of colors) {
console.log(color);
}
// 出力:
// 赤
// 青
// 緑
|
for文と比べて、インデックス変数を管理する必要がなくシンプルに書けます。
for…in文#
オブジェクトのプロパティ名(キー)を順番に取り出すための構文です。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
const person = {
name: "田中",
age: 30,
city: "東京",
};
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// 出力:
// name: 田中
// age: 30
// city: 東京
|
注意点として、for...inは配列に対しては使用を避けるべきです。配列にはfor...ofを使用しましょう。
forEachメソッド#
配列の各要素に対して関数を実行するメソッドです。
1
2
3
4
5
6
7
8
9
|
const numbers = [1, 2, 3];
numbers.forEach((num, index) => {
console.log(`インデックス${index}: ${num}`);
});
// 出力:
// インデックス0: 1
// インデックス1: 2
// インデックス2: 3
|
forEachはbreakやcontinueが使えない点に注意が必要です。
各構文の比較表#
| 構文 |
用途 |
breakの使用 |
インデックス取得 |
| for |
回数が決まった繰り返し |
可能 |
可能 |
| while |
条件ベースの繰り返し |
可能 |
手動で管理 |
| do…while |
最低1回実行する繰り返し |
可能 |
手動で管理 |
| for…of |
配列・イテラブルの反復 |
可能 |
entries()を使用 |
| for…in |
オブジェクトのキー反復 |
可能 |
キーとして取得 |
| forEach |
配列の各要素に関数適用 |
不可 |
コールバック引数 |
よくある間違いと注意点#
1. off-by-oneエラー(境界値の誤り)#
配列の処理で最もよくあるミスです。
1
2
3
4
5
6
7
8
9
10
11
|
const arr = ["a", "b", "c"];
// 悪い例: 範囲外アクセス
// for (let i = 0; i <= arr.length; i++) {
// console.log(arr[i]); // 最後がundefined
// }
// 良い例
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
|
配列のインデックスは0から始まり、最大インデックスはlength - 1であることを忘れないようにしましょう。
2. ループ内での配列操作#
ループ中に配列の長さを変更すると、予期しない動作を引き起こす可能性があります。
1
2
3
4
5
6
7
8
9
10
11
12
|
const numbers = [1, 2, 3, 4, 5];
// 悪い例: ループ中に配列を変更
// for (let i = 0; i < numbers.length; i++) {
// if (numbers[i] % 2 === 0) {
// numbers.splice(i, 1); // 要素を削除すると問題発生
// }
// }
// 良い例: 逆順でループするか、filterを使用
const oddNumbers = numbers.filter((num) => num % 2 !== 0);
console.log(oddNumbers); // [1, 3, 5]
|
3. 非同期処理との組み合わせ#
forEach内でasync/awaitを使っても、期待どおりに動作しないことがあります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const urls = ["url1", "url2", "url3"];
// 悪い例: 並列実行になり順序が保証されない
// urls.forEach(async (url) => {
// const data = await fetch(url);
// console.log(data);
// });
// 良い例: for...of と async/await を組み合わせる
async function fetchAll() {
for (const url of urls) {
// 実際のfetchの代わりにシミュレーション
console.log(`Fetching: ${url}`);
}
}
|
まとめ#
本記事では、JavaScriptの繰り返し処理について基本から実践的な使い方まで解説しました。
重要なポイントを振り返りましょう。
- for文: 繰り返し回数が明確な場合に使用。カウンタ変数の管理が一箇所にまとまる
- while文: 終了条件が動的に変化する場合に使用。条件が最初からfalseなら実行されない
- do…while文: 最低1回は処理を実行したい場合に使用
- break/continue: ループの制御に使用。breakは終了、continueはスキップ
- 無限ループの回避: カウンタ変数の更新忘れに注意し、安全装置として最大反復回数を設定する
繰り返し処理はプログラミングの基本中の基本です。それぞれの構文の特徴を理解し、適切な場面で使い分けることで、読みやすく保守しやすいコードを書けるようになります。
参考リンク#