Episode 1 — Fundamentals / 1.19 — Conditionals and Loops
1.19.e -- Break and Continue
In one sentence:
breakexits a loop immediately,continueskips the rest of the current iteration, and labeled statements let you target a specific outer loop -- whilereturninside a loop exits the entire function, not just the loop.
Navigation: <-- 1.19.d -- While and Do-While . 1.19.f -- Practice Problems -->
1. break -- exit the loop immediately
When break executes, the loop stops entirely and control moves to the first statement after the loop.
const numbers = [3, 7, 2, 9, 4, 1, 8];
for (const num of numbers) {
if (num === 9) {
console.log("Found 9! Stopping.");
break; // exit the loop
}
console.log(`Checked: ${num}`);
}
console.log("Loop ended.");
// Output:
// Checked: 3
// Checked: 7
// Checked: 2
// Found 9! Stopping.
// Loop ended.
Use cases for break:
- Searching for a value and stopping once found
- Terminating an otherwise-infinite loop when a condition is met
- Exiting early when further iteration is unnecessary
break in while loops
let input;
while (true) {
input = getNextCommand();
if (input === "quit") break;
processCommand(input);
}
// loop exits when user types "quit"
2. continue -- skip to the next iteration
When continue executes, the rest of the current iteration's body is skipped. The loop proceeds to the next iteration (checking the condition / running the update).
for (let i = 0; i < 10; i++) {
if (i % 2 !== 0) continue; // skip odd numbers
console.log(i);
}
// Output: 0, 2, 4, 6, 8
How continue affects different loops
| Loop type | What continue does |
|---|---|
for (init; cond; update) | Skips rest of body, runs update, then checks condition |
for...of / for...in | Skips rest of body, moves to next value/key |
while / do...while | Skips rest of body, jumps to condition check |
Warning in while loops: If continue skips the update statement, you can create an infinite loop:
// BUG -- infinite loop!
let i = 0;
while (i < 10) {
if (i === 5) continue; // skips i++ below when i is 5 -- stuck forever
console.log(i);
i++;
}
// FIX -- increment before continue
let j = 0;
while (j < 10) {
if (j === 5) {
j++; // increment first
continue;
}
console.log(j);
j++;
}
3. break vs continue comparison
break | continue | |
|---|---|---|
| Effect | Exits the entire loop | Skips current iteration, continues looping |
| Code after it | Not reached (for this loop) | Not reached (for this iteration only) |
| Loop continues? | No | Yes (next iteration) |
| Analogy | Leaving the building | Skipping one floor on the elevator |
// break example: find first negative
const values = [5, 3, -2, 8, -1];
let firstNeg;
for (const v of values) {
if (v < 0) {
firstNeg = v;
break; // stop searching
}
}
console.log(firstNeg); // -2
// continue example: sum only positives
let sum = 0;
for (const v of values) {
if (v < 0) continue; // skip negatives
sum += v;
}
console.log(sum); // 16 (5 + 3 + 8)
4. break in nested loops (only exits innermost)
break only exits the innermost loop it appears in:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (j === 1) break; // exits inner loop only
console.log(`i=${i}, j=${j}`);
}
}
// Output:
// i=0, j=0
// i=1, j=0
// i=2, j=0
// (j never reaches 2 because break exits the inner loop at j=1)
The outer loop continues running -- only the inner loop is broken.
5. Labeled statements with break and continue
To break or continue an outer loop from inside an inner loop, use a label.
Syntax
labelName: for (...) {
for (...) {
break labelName; // exits the LABELED loop
// or
continue labelName; // skips to next iteration of the LABELED loop
}
}
break with label -- exit outer loop
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
let found = false;
outerLoop: for (let r = 0; r < matrix.length; r++) {
for (let c = 0; c < matrix[r].length; c++) {
if (matrix[r][c] === 5) {
console.log(`Found 5 at row ${r}, col ${c}`);
found = true;
break outerLoop; // exits BOTH loops
}
}
}
// Output: "Found 5 at row 1, col 1"
Without the label, break would only exit the inner loop, and the outer loop would continue to the next row.
continue with label -- skip outer iteration
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (j === 1) continue outer; // skip to next i
console.log(`i=${i}, j=${j}`);
}
}
// Output:
// i=0, j=0
// i=1, j=0
// i=2, j=0
// (whenever j hits 1, the entire current outer iteration is skipped)
When to use labels
Labels are rare in production code. Most of the time you can:
- Extract the nested loop into a function and use
return - Use a flag variable to signal the outer loop
// Alternative to labeled break: extract to function
function findInMatrix(matrix, target) {
for (let r = 0; r < matrix.length; r++) {
for (let c = 0; c < matrix[r].length; c++) {
if (matrix[r][c] === target) {
return { row: r, col: c }; // return exits the function
}
}
}
return null;
}
6. return inside loops
return does not just exit the loop -- it exits the entire function.
function findIndex(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i; // exits the FUNCTION, not just the loop
}
}
return -1; // only reached if target was not found
}
console.log(findIndex([10, 20, 30], 20)); // 1
console.log(findIndex([10, 20, 30], 50)); // -1
Common confusion: Developers sometimes use break when they meant return, or vice versa.
| Statement | What it exits |
|---|---|
break | The innermost loop (or switch) |
continue | The current iteration of the innermost loop |
return | The entire function |
break label | The labeled loop |
continue label | The current iteration of the labeled loop |
7. When break/continue improve readability
Good uses
// 1. Early exit on search -- avoids unnecessary iterations
for (const user of users) {
if (user.id === targetId) {
result = user;
break; // clear intent: we found it, stop looking
}
}
// 2. Skip invalid items -- keeps main logic unindented
for (const record of records) {
if (!record.isValid) continue; // guard: skip bad data
// main processing here (not nested inside an if)
processRecord(record);
updateStats(record);
}
// 3. Sentinel exit from infinite loop
while (true) {
const msg = receiveMessage();
if (msg === null) break; // clean exit point
handleMessage(msg);
}
When they hurt readability
// BAD: Multiple continues and breaks make flow hard to follow
for (let i = 0; i < arr.length; i++) {
if (arr[i] < 0) continue;
if (arr[i] > 100) continue;
if (arr[i] % 2 !== 0) continue;
if (someCondition(arr[i])) break;
process(arr[i]);
}
// BETTER: Combine conditions or extract a function
for (let i = 0; i < arr.length; i++) {
const val = arr[i];
if (val >= 0 && val <= 100 && val % 2 === 0) {
if (someCondition(val)) break;
process(val);
}
}
// BEST: Extract to a function with filter + find
const valid = arr.filter(v => v >= 0 && v <= 100 && v % 2 === 0);
Rule of thumb: One break or continue per loop is usually fine. Multiple flow-control statements in the same loop body start to hurt.
8. break in switch vs break in loops
break means different things depending on context:
for (let i = 0; i < 5; i++) {
switch (i) {
case 2:
console.log("Hit case 2");
break; // exits the SWITCH, not the for loop
}
console.log(`After switch: i=${i}`); // still runs
}
To break out of the loop from inside a switch, you need a label:
loop: for (let i = 0; i < 5; i++) {
switch (i) {
case 3:
break loop; // exits the FOR loop
}
console.log(i);
}
// Output: 0, 1, 2
9. Real-world examples
Example 1 -- Search and stop
function findFirstPrime(numbers) {
for (const n of numbers) {
if (n < 2) continue; // skip non-candidates
let isPrime = true;
for (let d = 2; d <= Math.sqrt(n); d++) {
if (n % d === 0) {
isPrime = false;
break; // no need to check more divisors
}
}
if (isPrime) return n; // return exits the function
}
return null;
}
console.log(findFirstPrime([4, 6, 8, 11, 15])); // 11
Example 2 -- Skip invalid items in data processing
const rawRecords = [
{ id: 1, name: "Alice", age: 30 },
{ id: 2, name: "", age: 25 }, // invalid: empty name
{ id: 3, name: "Bob", age: -5 }, // invalid: negative age
{ id: 4, name: "Carol", age: 28 },
null, // invalid: null record
];
const validRecords = [];
for (const record of rawRecords) {
if (!record) continue; // skip null/undefined
if (!record.name) continue; // skip empty names
if (record.age < 0) continue; // skip bad ages
validRecords.push(record);
}
console.log(validRecords);
// [{ id: 1, ... "Alice" ... }, { id: 4, ... "Carol" ... }]
Example 3 -- Early termination in a game
function playRound(players) {
for (const player of players) {
if (player.health <= 0) continue; // skip eliminated players
const action = player.chooseAction();
if (action === "surrender") {
console.log(`${player.name} surrenders!`);
break; // round ends immediately
}
executeAction(player, action);
}
}
Key takeaways
breakexits the innermost loop (or switch) immediately.continueskips the rest of the current iteration and moves to the next one.- In nested loops,
break/continueonly affect the innermost loop unless you use a label. returninside a loop exits the entire function -- it is more powerful thanbreak.- Use
break/continueto make intent clear, but avoid multiple flow-control statements in one loop body.
Explain-It Challenge
Explain without notes:
- What is the difference between
breakandreturninside a loop that is inside a function? - In a nested loop, how do you break out of the outer loop from inside the inner loop?
- Why can
continuecause an infinite loop in awhileloop but not in aforloop?
Navigation: <-- 1.19.d -- While and Do-While . 1.19.f -- Practice Problems -->