1.

for文の使い方|初期化・条件・更新式とbreak・continue

編集
この記事の要点
  • for文「決められた回数」繰り返す制御構造。初期化・条件式・更新式の 3 つを 1 行で書くのが特徴
  • 構文は for (初期化; 条件式; 更新式) { 処理 }。各構成要素はセミコロン区切り
  • 初期化はループに入る前に 1 回だけ実行、条件式が true の間ループ、更新式は毎回末尾で実行
  • break でループを抜け、continue で次の繰り返しへ。多重ループは内側ループのみ抜ける
  • JavaScript には for...of(配列要素)と for...in(オブジェクトキー)もあり、用途に応じて使い分ける

for文とは

for文あらかじめ決められた回数処理を繰り返すための制御構造です。while 文と違ってカウンタ変数の初期化・条件・更新を 1 行で書けるのが特徴で、回数指定のループでは最もよく使われます。

基本構文

構成要素説明実行タイミング
初期化カウンタ変数の宣言・初期値ループ開始前に 1 回だけ
条件式繰り返しを続けるかの判定各反復の先頭で評価
更新式カウンタ変数の更新各反復の末尾で実行

JavaScript

for (let i = 0; i < 5; i++) {
  console.log(i);
}
// 0
// 1
// 2
// 3
// 4

Java

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}
// 0
// 1
// 2
// 3
// 4

実行の流れ

  1. 初期化 i = 0 実行
  2. 条件式 i < 5 を評価 → true なら本体を実行、false ならループ終了
  3. 本体を実行(console.log(i)
  4. 更新式 i++ 実行
  5. ステップ 2 へ戻る

逆順ループ

for (let i = 10; i > 0; i--) {
  console.log(i);
}
// 10, 9, 8, ..., 1

ステップを変える

// 2 ずつ増加
for (let i = 0; i < 10; i += 2) {
  console.log(i);   // 0, 2, 4, 6, 8
}

// 3 ずつ減少
for (let i = 100; i > 0; i -= 3) {
  // ...
}

配列の走査

const arr = ["apple", "banana", "cherry"];

for (let i = 0; i < arr.length; i++) {
  console.log(i, arr[i]);
}
// 0 apple
// 1 banana
// 2 cherry

break と continue

キーワード意味
breakループを完全に抜ける
continue残りをスキップして次の反復へ
// break: 5 に達したら抜ける
for (let i = 0; i < 100; i++) {
  if (i === 5) break;
  console.log(i);  // 0, 1, 2, 3, 4
}

// continue: 偶数だけ表示
for (let i = 0; i < 10; i++) {
  if (i % 2 !== 0) continue;
  console.log(i);  // 0, 2, 4, 6, 8
}

ネストした for 文

九九の表のように、for 文を入れ子にすると多次元の繰り返しが書けます。

for (let i = 1; i <= 3; i++) {
  for (let j = 1; j <= 3; j++) {
    process.stdout.write(`${i * j}\t`);
  }
  console.log();
}
// 1  2  3
// 2  4  6
// 3  6  9

無限ループ

条件式を省略するか true にすると無限ループになります。必ず breakreturn で抜ける処理を入れます。

for (;;) {
  // 何かする
  if (条件) break;
}

JavaScript の派生形

構文用途
for (let i...)カウンタ付きループ(伝統的)
for (const x of arr)配列・iterable のを反復
for (const k in obj)オブジェクトのキーを反復
arr.forEach(fn)関数を各要素に適用
const arr = ["a", "b", "c"];

// for...of: 配列の値
for (const v of arr) {
  console.log(v);   // a, b, c
}

// for...in: オブジェクトのキー
const obj = { name: "Alice", age: 30 };
for (const k in obj) {
  console.log(k, obj[k]);
  // name Alice
  // age 30
}

Java の拡張 for(for-each)

int[] nums = {10, 20, 30};
for (int n : nums) {
    System.out.println(n);
}
// 10
// 20
// 30

よくあるバグ

  • off-by-one: <<= を取り違えて 1 周多い・少ない
  • 無限ループ: 更新式を書き忘れる / 条件式が永久に true
  • 添字の踏み外し: 配列長と条件式の不一致による IndexOutOfBoundsException
  • ループ内で配列を変更: イテレート中に push / splice すると挙動が乱れる

多重ループから一気に抜ける

ネストした for を一気に抜けたいとき、JavaScript ではラベル付き break、Java もラベル付き break が使えます。

outer:
for (let i = 0; i < 5; i++) {
  for (let j = 0; j < 5; j++) {
    if (i * j > 6) {
      console.log(`break at i=${i} j=${j}`);
      break outer;     // 外側ループまで一気に抜ける
    }
  }
}
outer:
for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            System.out.println("break at i=" + i + " j=" + j);
            break outer;
        }
    }
}

初期化と更新式に複数文

カンマ演算子で初期化や更新を複数書けます。読みづらくなりがちなので使いすぎ注意。

// 2 つのカウンタを同時に動かす
for (let i = 0, j = 10; i < j; i++, j--) {
  console.log(i, j);
}
// 0 10
// 1 9
// 2 8
// 3 7
// 4 6

配列要素を逆順で削除する

ループ内で配列要素を削除する場合は後ろから走査するのが鉄則。前から削除するとインデックスがズレて要素を飛ばします。

const arr = [1, 2, 3, 4, 5, 6];

// 偶数だけ削除(逆順)
for (let i = arr.length - 1; i >= 0; i--) {
  if (arr[i] % 2 === 0) {
    arr.splice(i, 1);
  }
}
console.log(arr);   // [1, 3, 5]

パフォーマンスのコツ

テクニック効果
arr.length のキャッシュ毎回プロパティ取得しないので僅かに高速
条件式に複雑な計算を入れない毎反復で評価されるので事前計算する
不要なオブジェクト生成を避けるGC 負荷を減らす
// 改善前: arr.length が毎回評価される
for (let i = 0; i < arr.length; i++) { ... }

// 改善後: 長さをキャッシュ
for (let i = 0, n = arr.length; i < n; i++) { ... }

FAQ

Q: for / while の使い分けは?
A: 回数が明確に決まっているなら for、条件次第で終わるなら while が読みやすいです。

Q: 大きな配列は for と forEach どちらが速い?
A: 通常は for の方が僅かに速いですが、可読性とのトレードオフ。1 万件程度なら差は感じません。

Q: letvar の違いは?
A: JavaScript で for (let i...) と書くと、反復ごとに新しい i が生成されるため、コールバック中の i が壊れません。var はループ後の値で固定されるためハマりやすいです。

Q: 無限ループを止めるには?
A: 必ず break で抜ける条件を入れる、または条件式が必ず false になるよう更新式を確認します。

Q: for...of で index が欲しい
A: for (const [i, v] of arr.entries()) でインデックスと値の両方を取れます。

関連

  • while 文 — 条件のみの繰り返し
  • do-while 文 — 必ず 1 回は実行する繰り返し
  • break / continue — ループの制御
  • for...of / for...in — JavaScript の派生形
  • forEach / map / filter — 関数型の反復
  • ラベル付き break — 多重ループ脱出
編集
Post Share
子ページ

子ページはありません

同階層のページ

同階層のページはありません

最近更新/作成されたページ