JavaScript のラベル付き break / continue を初心者向けに
「なんでここでループが止まるんだろう?」——ネストしたループで迷子になりがちなところを、例題でスッキリさせます。まずは基本から、少しずつステップアップしましょう。
ループと break / continue の基本
- ループの役割: 同じ処理を何回も繰り返すための仕組み。
forやwhileが代表的。 - break: 今いるループを「途中で終了」する。以降の繰り返しはしない。
- continue: 今いるループの「今回の処理をスキップ」して、次の繰り返しへ進む。
for (let i = 1; i <= 5; i++) {
if (i === 3) {
continue; // 3のときだけスキップ
}
if (i === 4) {
break; // 4が来たらループを終了
}
console.log(i); // 1, 2 が出力される
}
JavaScriptラベルってなに?
- ラベルの正体: 文(ループ)に「名前」をつける仕組み。
名前:と書いてから文を続ける。 - どこで使う: 主に「ネスト(入れ子)されたループ」で、外側のループに対して
breakやcontinueを効かせたいときに使う。 - ないと困る場面:
break/continueは通常「一番内側のループ」にしか届かないため、外側を止めたい・飛ばしたい場合に届かない。
outerLoop: for (let i = 1; i <= 3; i++) {
// outerLoop というラベルを外側のループにつけた
for (let j = 1; j <= 3; j++) {
console.log(i, j);
}
}
JavaScript例題1: ラベル付き break(外側ごと止める)
- 目的: 条件を満たしたら「内側だけじゃなく、外側のループごと終了」したい。
- 使いどころ: もう先に進む意味がない、早退したい(早期終了)。
outer: for (let i = 1; i <= 3; i++) {
for (let j = 1; j <= 3; j++) {
const product = i * j;
console.log(`i=${i}, j=${j}, i*j=${product}`);
if (product > 5) {
// 外側のループ outer を終了
break outer;
}
}
}
JavaScript- 実行の流れ:
i=1, j=1→i=1, j=2→i=1, j=3→i=2, j=1→i=2, j=2(ここで 2×2=4)→i=2, j=3(ここで 2×3=6)で条件成立、外側ごと終了。 - ポイント:
break outer;と書くことで、「どのループを止めたいか」を明示できる。
例題2: ラベル付き continue(外側の次の周回へ)
- 目的: 条件を満たしたら「外側のループの次の繰り返し」へ進みたい(現在の外側 i の周回を終えて i+1 へ)。
- 使いどころ: 今の外側の組み合わせはもう不要、次の外側のケースに移りたい。
outer: for (let i = 1; i <= 3; i++) {
for (let j = 1; j <= 3; j++) {
if (i === j) {
// i と j が同じになったら、外側の次の繰り返しへ
continue outer;
}
console.log(`pair: (${i}, ${j})`);
}
}
JavaScript- 実行の流れ(要点):
i=1のときj=1で条件成立→外側のi=2へジャンプ。i=2のときj=2で成立→i=3へ。i=3のときj=3で成立→外側終了。 - ポイント: 単なる
continue;だと「内側 j の次」へ進むだけだが、continue outer;は「外側 i の次」へ進む。
例題3: 九九表から特定の列で打ち切る(応用)
- 目的: 九九を出力しつつ、「ある条件で全体を打ち切り」たい。
- 学べること: ラベルなしの
breakとラベルありのbreakの違いが体感できる。
// ラベルなし(内側しか止まらない)
for (let i = 1; i <= 9; i++) {
for (let j = 1; j <= 9; j++) {
if (j === 5) break; // 内側の j ループだけ終了、i は続く
console.log(`${i} x ${j} = ${i * j}`);
}
}
// ラベルあり(外側も止める)
stopAll: for (let i = 1; i <= 9; i++) {
for (let j = 1; j <= 9; j++) {
if (j === 5) break stopAll; // 全体終了
console.log(`${i} x ${j} = ${i * j}`);
}
}
JavaScript- 違いの核心: 前者は「各行の 5 列目で行内を打ち切る」だけ。後者は「最初に 5 列目に達した瞬間、表全体を終了」する。
いつ使う?注意点と設計のヒント
- 便利な場面:
- 早期終了: 目的が達成されたら即終了(検索・探索・検証の途中で十分な条件を満たしたなど)。
- スキップ最適化: 今の外側ケースが無意味とわかったら次へ進む。
- 注意点:
- 読みやすさ: ラベルが増えると追跡が難しくなる。名前は短く意味が伝わるものに。
- 過度なネスト: 深い入れ子はそもそも読みにくい。関数化やロジックの分割で解消できることも多い。
- 代替策: 早期 return(関数に切り出して条件成立時に return)や、フラグ変数で制御する方法も検討。
- 小さなルール:
- スコープ: ラベルはつけた文の直前に書く。離れた場所には効かない。
- 一貫性:
break/continue先のラベルは「存在する外側のループ」を指すこと。別の文を指すと分かりにくくなる。
ミニ練習問題
- 課題1: 2重ループで、合計が 10 を超えたら「外側ごと」終了するコードを書いてください。
例:iとjを 1..5 で回し、i + j > 10の瞬間にbreakで外側を止める。
endAll: for (let i = 1; i <= 5; i++) {
for (let j = 1; j <= 5; j++) {
if (i + j > 10) break endAll;
console.log(i, j);
}
}
JavaScript- 課題2: 2重ループで、
iが偶数かつjが奇数なら「外側の次の i」へ進むコードを書いてください。
nextI: for (let i = 1; i <= 4; i++) {
for (let j = 1; j <= 4; j++) {
if (i % 2 === 0 && j % 2 === 1) continue nextI;
console.log(`i=${i}, j=${j}`);
}
}
JavaScript- 課題3: ラベルを使わずに同じ挙動を作るにはどうするか試してください。
- ヒント: 関数に切り出して、条件成立時に
returnする。
- ヒント: 関数に切り出して、条件成立時に
