JavaScript Break Continue
break and continue are jump statements that change the normal, top-to-bottom flow of a loop. break exits a loop (or a switch) immediately, while continue skips the rest of the current iteration and jumps straight to the next one. Together they let you write loops that stop early when you’ve found what you need, or skip over values you don’t care about, instead of relying on complicated nested conditionals.
Overview: How Loops and Jump Statements Work
A loop (for, while, do...while, for...of, for...in) normally runs its body once per iteration until its condition becomes false. Internally, the JavaScript engine tracks a loop as a single control structure with three parts it manages automatically: the test condition, the body, and (for for loops) the update expression. On every pass, it evaluates the condition, and if true, executes the body from top to bottom, then loops back around.
break and continue hook directly into that control structure:
breaktells the engine “stop managing this loop entirely — jump to the first line of code after the loop’s closing brace.” No further conditions are checked and no further iterations happen.continuetells the engine “stop executing the body for this iteration, but don’t abandon the loop — go straight to the update step (forforloops) or the condition check (forwhileloops) and keep going.”
Both statements only make sense inside an enclosing loop (or, for break, inside a switch statement too). If you write break or continue outside any loop or switch, or inside a nested function that isn’t itself a loop, JavaScript throws a SyntaxError at parse time — before your code even runs. This is a compile-time check, not a runtime one, which is why it’s called an “illegal” statement rather than a thrown exception.
Syntax
break;
break label;
continue;
continue label;
label: for (...) {
// loop body
}
| Form | Meaning |
|---|---|
break; |
Exits the nearest enclosing loop or switch immediately. |
continue; |
Skips to the next iteration of the nearest enclosing loop. |
label: |
An identifier placed before a loop, letting break/continue target that specific loop instead of the innermost one. |
break label; |
Exits the labeled loop entirely, even from inside a nested loop. |
continue label; |
Skips to the next iteration of the labeled (outer) loop, not the innermost one. |
A label is just an identifier followed by a colon, placed directly before the loop keyword. It is not a string, and it lives in its own namespace — it won’t collide with variable names.
Examples
Example 1: Using break to stop searching early
const numbers = [4, 9, 15, 23, 30, 42];
let firstOver20;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > 20) {
firstOver20 = numbers[i];
break;
}
}
console.log(`First number over 20: ${firstOver20}`);
console.log(`Loop stopped early, did not check all ${numbers.length} numbers`);
Output:
First number over 20: 23
Loop stopped early, did not check all 6 numbers
As soon as numbers[i] > 20 becomes true at index 2 (value 23), break exits the loop immediately. The engine never looks at 30 or 42, even though they also satisfy the condition — this is exactly what makes break efficient for “find the first match” logic.
Example 2: Using continue to skip values
for (let i = 1; i <= 10; i++) {
if (i % 3 === 0) {
continue;
}
console.log(i);
}
Output:
1
2
4
5
7
8
10
Every time i is a multiple of 3, continue skips the console.log(i) line for that iteration only — the loop doesn’t stop, it just moves on to increment i and check the condition again. Notice that 3, 6, and 9 are missing from the output, but the loop still counts all the way up to 10.
Example 3: Labeled break in nested loops
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
let found = null;
outer: for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col] === 5) {
found = { row, col };
break outer;
}
}
}
console.log(found);
Output:
{ row: 1, col: 1 }
A plain break inside the inner loop would only exit the inner loop, leaving the outer row loop to keep running unnecessarily. By labeling the outer loop outer: and writing break outer;, both loops stop the moment the value 5 is found, avoiding wasted iterations over the rest of the matrix.
Under the Hood: Step by Step
Walking through Example 3 helps show exactly what the engine does:
- The engine enters the outer loop, sets
row = 0, and enters the inner loop withcol = 0. - For each
col, it checksmatrix[row][col] === 5. On row 0, none of the values match, so the inner loop finishes normally and the outer loop advances torow = 1. - On row 1,
col = 1givesmatrix[1][1] === 5, which is true. The engine assignsfoundand executesbreak outer;. - Because the label targets the outer loop, the engine discards both the remaining inner-loop iterations and the remaining outer-loop iterations, jumping straight to the line after the outer loop’s closing brace.
This is fundamentally different from a plain break in that spot: without the label, only the inner loop would stop, and the outer loop would proceed to row = 2, checking row 2 pointlessly.
Common Mistakes
Mistake 1: Using break or continue inside a callback like forEach
A very common mistake is trying to break out of an Array.prototype.forEach call:
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num) => {
if (num === 3) {
break;
}
console.log(num);
});
This throws SyntaxError: Illegal break statement and won’t even parse. The callback passed to forEach is its own function — break can only target a loop or switch in the same function scope, and there is no loop inside that arrow function for it to break out of. forEach itself has no built-in way to stop early.
The fix is to use an actual loop construct that supports break, such as for...of:
const numbers = [1, 2, 3, 4, 5];
for (const num of numbers) {
if (num === 3) {
break;
}
console.log(num);
}
Output:
1
2
If you specifically need to find something rather than just stop iterating, array methods like .find(), .some(), or .every() are often an even cleaner alternative, since they’re designed to short-circuit internally.
Mistake 2: continue skipping the update step and causing an infinite loop
In a while loop, the increment isn’t automatic the way it is in a for loop — you have to write it yourself. If continue appears before the line that updates the loop variable, it skips that update every time the condition is met, and the loop condition never changes. For example, writing if (i === 2) { continue; } followed later by i++; means that once i reaches 2, continue always fires before i++ runs, so i is stuck at 2 forever — the loop never terminates.
The fix is to make sure any variable the loop condition depends on is updated before the continue check, not after it:
let i = 0;
while (i < 5) {
i++;
if (i === 3) {
continue;
}
console.log(i);
}
Output:
1
2
4
5
Because i++ now runs first, every path through the loop body updates i, so the loop is guaranteed to eventually reach its exit condition regardless of when continue fires.
Best Practices
- Reach for
breakwhen you’re searching and want to stop as soon as a condition is satisfied — it avoids scanning the rest of a collection needlessly. - Use
continueto handle “skip this one” cases at the top of a loop body, which keeps the rest of the body free of an extra layer ofifnesting. - Prefer array methods (
.find(),.some(),.every(),.filter()) over manual loops withbreak/continuewhen you’re just testing or searching a collection — they read more declaratively. - Use labeled
break/continuesparingly, only for nested loops where a plainbreakwould be ambiguous or insufficient; overusing labels can make control flow harder to follow. - Never use
breakorcontinueinside a callback function (like the one passed toforEach,map, orsetTimeout) — they only work in the function scope where the loop itself is written. - In
whileanddo...whileloops, always double-check that every branch, including ones withcontinue, still updates whatever variable controls the loop’s exit condition.
Practice Exercises
- Exercise 1: Write a
forloop over the numbers 1 through 20 that logs each number, but stops completely (usingbreak) as soon as it reaches a number greater than 12. - Exercise 2: Given an array of words, use
continueinside afor...ofloop to log only the words with more than 4 letters, skipping shorter ones. - Exercise 3: Write two nested loops representing a 4×4 grid of numbers 1-16. Use a labeled
breakto stop both loops as soon as you find the number 10, and log the row and column where it was found.
Summary
breakexits the nearest enclosing loop (orswitch) immediately, skipping any remaining iterations.continueskips only the rest of the current iteration and moves on to the next one — the loop keeps running.- Both statements are checked at parse time: using them outside a loop or switch, or inside a nested callback function, causes a
SyntaxErrorbefore the code runs. - Labels (
label: for (...) {...}) letbreak label;andcontinue label;target an outer loop from inside a nested one. - In
while/do...whileloops, make sure the loop’s update logic runs before anycontinuecheck to avoid accidental infinite loops. - For simple searches, array methods like
.find()or.some()are often clearer than manual loops withbreak.
