Episode 1 — Fundamentals / 1.19 — Conditionals and Loops

1.19.e -- Break and Continue

In one sentence: break exits a loop immediately, continue skips the rest of the current iteration, and labeled statements let you target a specific outer loop -- while return inside 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 typeWhat continue does
for (init; cond; update)Skips rest of body, runs update, then checks condition
for...of / for...inSkips rest of body, moves to next value/key
while / do...whileSkips 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

breakcontinue
EffectExits the entire loopSkips current iteration, continues looping
Code after itNot reached (for this loop)Not reached (for this iteration only)
Loop continues?NoYes (next iteration)
AnalogyLeaving the buildingSkipping 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.

StatementWhat it exits
breakThe innermost loop (or switch)
continueThe current iteration of the innermost loop
returnThe entire function
break labelThe labeled loop
continue labelThe 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

  1. break exits the innermost loop (or switch) immediately.
  2. continue skips the rest of the current iteration and moves to the next one.
  3. In nested loops, break/continue only affect the innermost loop unless you use a label.
  4. return inside a loop exits the entire function -- it is more powerful than break.
  5. Use break/continue to make intent clear, but avoid multiple flow-control statements in one loop body.

Explain-It Challenge

Explain without notes:

  1. What is the difference between break and return inside a loop that is inside a function?
  2. In a nested loop, how do you break out of the outer loop from inside the inner loop?
  3. Why can continue cause an infinite loop in a while loop but not in a for loop?

Navigation: <-- 1.19.d -- While and Do-While . 1.19.f -- Practice Problems -->