JAVASCRIPT / LOOPS
break, continue, and labelled exits
Stop a loop early with break, skip a single iteration with continue, and use labels to aim either one at an outer loop instead of the nearest one.
What you will learn
- Use break to leave a loop entirely and continue to end only the current iteration
- Label an outer loop, then aim break or continue at it from inside a nested loop
- Remember that break inside a switch ends the switch, not the enclosing loop
- Swap forEach for for...of when the loop needs a genuine early exit
Understanding break, continue, and labelled exits
A loop body normally runs to its closing brace and then hands control back to the loop machinery. break and continue are the two ways to leave that body early: break abandons the whole loop statement and resumes at the first line after it, while continue abandons only the rest of the current iteration. The distinction matters most in a for loop, where continue still runs the update expression such as i++, because the update belongs to the loop header and not to the body. Used bare, both keywords always talk to the innermost loop that encloses them.
A label is a name attached to a statement, written as an identifier followed by a colon directly before it, as in outer: for (...) {}. Once a loop carries a label, break outer leaves that loop no matter how many inner loops you are standing in, and continue outer jumps to that loop's next iteration, discarding the remainder of every body in between. Think of the label as a pointer to a specific loop: break and continue then address that loop rather than the nearest one. continue only accepts a label that names a loop, while break accepts any labelled statement, including a plain block.
These keywords are resolved lexically and stop at function boundaries, which is why you cannot break out of array.forEach: the callback is a function, so break there is a syntax error and return ends only that one call. When callback-style iteration needs an early exit, switch to for...of or use a method designed to stop, such as some, every, or find. Labels exist because JavaScript has no goto and abandoning a nested search is a common need; the alternatives are a found flag tested in both loop conditions, or moving the nested loops into a function and using return.
const grid = [
[4, 2, 8],
[6, 3, 9],
[7, 1, 5],
];
let hit = null;
search:
for (let r = 0; r < grid.length; r++) {
for (let c = 0; c < grid[r].length; c++) {
const n = grid[r][c];
if (n % 2 === 0) continue; // even: abandon this cell only
console.log(`odd candidate ${n} at [${r}][${c}]`);
if (n > 6) {
hit = { r, c, n };
break search; // leaves both loops at once
}
}
}
console.log(`first match: ${hit.n} at row ${hit.r}, column ${hit.c}`);break and continue always act on the innermost enclosing loop unless a label points them at an outer one.
Worked examples
break inside a switch stops the switch
Shows that a bare break in a switch never reaches the surrounding loop, and how a label fixes it.
const events = ['click', 'error', 'scroll'];
for (const e of events) {
switch (e) {
case 'error':
console.log('error seen');
break;
default:
console.log(`ok: ${e}`);
}
}
scan:
for (const e of events) {
switch (e) {
case 'error':
console.log('error seen, aborting scan');
break scan;
default:
console.log(`ok: ${e}`);
}
}Example explained
Line 1The bare break on the error case ends the switch statement, so the first loop still goes on to print ok: scroll.
Line 2scan: names the second for...of, so break scan; leaves the loop and not just the switch.
Line 3Nothing prints after aborting scan because control resumes below the labelled loop.
Line 4A switch captures break but not continue: continue inside a switch still belongs to the loop around it.
continue with a label restarts the outer loop
Demonstrates continue targeting an outer loop to abandon a partially processed group and move to the next one.
const carts = [
{ id: 'a', items: [2, 5, 0] },
{ id: 'b', items: [4, 7] },
{ id: 'c', items: [1, 3] },
];
nextCart:
for (const cart of carts) {
let total = 0;
for (const price of cart.items) {
if (price === 0) {
console.log(`${cart.id}: price of 0 found, abandoning this cart`);
continue nextCart;
}
total += price;
}
console.log(`${cart.id}: total ${total}`);
}Example explained
Line 1continue nextCart; ends the current outer iteration, so the total line below the inner loop is skipped for cart a.
Line 2Cart b never sees a zero, so its inner loop finishes normally and the total prints.
Line 3Using break nextCart instead would have stopped after cart a and never touched b or c.
Line 4A bare continue here would only skip the zero price and still print a wrong total of 7 for cart a.
forEach cannot be broken
Contrasts return inside a forEach callback with a real break in for...of.
const codes = [200, 204, 500, 200];
codes.forEach((c) => {
if (c >= 500) return; // ends this callback call only
console.log(`forEach saw ${c}`);
});
for (const c of codes) {
if (c >= 500) {
console.log(`for...of stopped at ${c}`);
break;
}
console.log(`for...of saw ${c}`);
}Example explained
Line 1return in the callback behaves like continue: forEach still calls it for the final 200.
Line 2Writing break in that callback would not even run; it is a syntax error because the callback is a function, not a loop body.
Line 3The for...of version reaches break, so the last 200 is never visited.
Line 4codes.some(c => c >= 500) is the idiomatic choice when you only need to know whether an early exit condition was met.
Important notes
A label is an identifier, not a string, and it must sit on a statement that encloses the break or continue, so you cannot jump forward into a loop you have not entered yet.
break label also works on a labelled block, as in done: { ... break done; }, which skips the rest of that block; it is legal but usually clearer as a function with a return.
Common mistakes
Calling break inside a switch that sits in a loop: only the switch ends, the loop keeps iterating, and the abort condition looks like it was ignored.
Using continue in a while loop whose counter is incremented at the bottom of the body: the increment is skipped, the condition never changes, and the loop never ends.
Putting break in a forEach callback, which throws Illegal break statement; changing it to return runs but silently skips just one element instead of stopping.
Try it yourself
Change, predict, then run
In a browser console, loop over [['hi', ''], ['sun', 'melon'], ['', 'orange']] with continue skipping empty strings, and use a labelled break to stop at the first word of five or more letters. Log that word together with its outer and inner index.
Open the JavaScript workspaceCheck your understanding
What does this print? outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (j === 1) continue outer; console.log(i, j); } }
- 0 0, 1 0, 2 0
- 0 0 only
- 0 0, 0 2, 1 0, 1 2, 2 0, 2 2
- 0 0, 1 0, 2 0, then it loops forever
Show answer
continue outer ends the current iteration of the labelled loop, so the outer header's i++ still runs and the outer loop advances normally to 3 and stops; each row therefore prints only its j = 0 line. The 0 0, 0 2, 1 0, ... answer is what a bare continue would print, since that would skip only j === 1 inside the inner loop, and 0 0 only is what break outer would give.