Module: JavaScript
JavaScript·048·4 MIN READ

048: Loops and Iteration

TOPICS COVERED: Loops and Iteration

Outcomes

By the end of this lesson, you can:

  • explain when repeated work needs iteration;
  • trace initialization, condition, body, and update in a for loop;
  • use a while loop when repetition depends on a changing condition;
  • process array values and accumulate a summary;
  • use break and continue deliberately; and
  • recognize and fix off-by-one and infinite-loop errors.

Prerequisites and Retrieval

Retrieve conditions, arrays as ordered values, and reassignment.

  1. What does count < 5 produce?
  2. Why must an accumulating total use let?
  3. Which branch runs first in an else if chain?

The array method lessons come later. Today, process lists with explicit loops so every iteration is visible.

Terms

  • loop/iteration: Repeating statements until a condition ends the cycle. — Source: MDN: Looping code
  • iteration: One pass of the loop body. — Source: MDN: Loops and iteration
  • counter: Variable tracking loop progress, typically incremented each pass. — Source: MDN: Loops and iteration
  • initializer: Starting expression setting the counter before iteration begins. — Source: MDN: for
  • condition: Per-pass test deciding whether the body runs again. — Source: MDN: for
  • update: After-expression adjusting state at end of each pass. — Source: MDN: for
  • accumulator: Variable collecting a running total/result across iterations. — Source: MDN: Loops and iteration
  • break: Exits the nearest enclosing loop immediately. — Source: MDN: break
  • continue: Skips to the next iteration without leaving the loop. — Source: MDN: continue
  • nested loop: A loop inside another loop’s body. — Source: MDN: Loops and iteration
  • off-by-one error: Boundary mistake producing one extra/fewer pass (< vs <=, index math). — Source: MDN: Loops and iteration
  • infinite loop: Loop whose exit condition never becomes false. — Source: MDN: Loops and iteration
  • Iteration (official): "Iteration is repeating a set of instructions until a condition is met." — Source: MDN: Iteration protocols
  • Loop invariant: "A condition that must hold before and after each iteration." — Source: ECMAScript: Iteration Statements

Beginner Explanation and Mental Model

A loop is a controlled replay button. Instead of writing five nearly identical statements, define where repetition starts, when it continues, what happens each pass, and how progress changes.

A for loop places those controls together:

js
for (let index = 0; index < 3; index += 1) {
  console.log(index);
}

Trace it:

  1. let index = 0 runs once.
  2. index < 3 is checked. If false, the loop ends.
  3. The body runs.
  4. index += 1 updates progress.
  5. Steps 2-4 repeat.

It logs 0, 1, and 2. The condition is false at 3. This aligns with zero-based array indexes: a list of length 3 has valid indexes 0 through 2, so index < list.length is the standard boundary.

A trace table is the safest beginner debugging tool. Create columns for the counter, condition result, current item, and accumulator after the body. Include a final row where the condition becomes false; that row explains why execution stops. If the expected number of passes is five, identify all five counter values before running the code. This catches a mistaken starting value or comparison without relying on trial and error.

A while loop exposes only the condition in its header:

js
let attempts = 0;
while (attempts < 3) {
  console.log("Attempt", attempts + 1);
  attempts += 1;
}

Choose for when initialization, update, and boundary form a clear counting sequence. Choose while when continuation depends on a state whose number of repetitions is not the main idea. Every while loop needs a believable path that makes its condition false.

Processing and accumulating

To summarize values, initialize an accumulator before the loop and update it inside:

js
const values = [4, 7, 2];
let total = 0;

for (let index = 0; index < values.length; index += 1) {
  total += values[index];
}

The array remains const; the total is let because it is rebound each pass. values[index] selects the current item.

break, continue, and nesting

break leaves the loop when further work is unnecessary. continue skips only the current iteration. Use either sparingly; too many jumps make control flow difficult to trace.

A nested loop repeats an inner sequence for each outer pass, useful for a small grid. If each loop runs 3 times, the body runs 9 times. Work grows quickly, so nesting must have a clear purpose.

Worked Example: Number Summary

js
const numbers = [12, 5, 8, 21, 4];
let total = 0;
let evenCount = 0;
let largest = numbers[0];

for (let index = 0; index < numbers.length; index += 1) {
  const currentNumber = numbers[index];
  total += currentNumber;

  if (currentNumber % 2 === 0) {
    evenCount += 1;
  }

  if (currentNumber > largest) {
    largest = currentNumber;
  }
}

const average = total / numbers.length;
console.log("Total:", total);
console.log("Even count:", evenCount);
console.log("Largest:", largest);
console.log("Average:", average);

Expected output:

text
Total: 50
Even count: 3
Largest: 21
Average: 10

Before each iteration, write a trace row containing index, currentNumber, total, evenCount, and largest. Initializing largest with the first element works for negative lists too; initializing it to 0 would fail for [-8, -3]. This example assumes a non-empty array. Empty-input handling belongs in validation logic.

Intermediate Example: Skip and Stop

Process readings, skip negative invalid readings, and stop at a sentinel value of 999:

js
const readings = [14, -1, 18, 999, 22];
let validTotal = 0;
let validCount = 0;

for (let index = 0; index < readings.length; index += 1) {
  const reading = readings[index];

  if (reading === 999) {
    break;
  }

  if (reading < 0) {
    continue;
  }

  validTotal += reading;
  validCount += 1;
}

console.log("Valid count:", validCount);
console.log("Valid total:", validTotal);

Expected output:

text
Valid count: 2
Valid total: 32

-1 reaches continue, so accumulator updates are skipped. 999 reaches break, so 22 is never visited. Put stop conditions before skip conditions if a sentinel might otherwise satisfy a skip rule.

A simple nested-loop concept:

js
for (let row = 1; row <= 2; row += 1) {
  for (let column = 1; column <= 3; column += 1) {
    console.log(`Row ${row}, column ${column}`);
  }
}

This prints six coordinates. The inner loop completes all three columns for each row.

Optional Advanced Extension: for...of

When only values matter, for...of is clearer than manually indexing an array:

js
const prices = [100, 250, 50];
let total = 0;

for (const price of prices) {
  total += price;
}

console.log(total); // 400

The per-iteration price binding is const because that binding is not reassigned during its pass. Do not use for...in for array values; it enumerates property keys and has different semantics.

Deep Dive: for, for...of, and for...in

Choose a loop based on what you are iterating.

js
for (let index = 0; index < items.length; index += 1) {
  console.log(index, items[index]);
}

Use a classic for when you need explicit index control.

js
for (const item of items) {
  console.log(item);
}

Use for...of for iterable values such as arrays, strings, maps, and sets.

js
const stock = { biryani: 10, juice: 4 };

for (const key in stock) {
  if (Object.hasOwn(stock, key)) {
    console.log(key, stock[key]);
  }
}

Use for...in for enumerable property keys, typically on objects. Do not use it as your default array loop.

do...while

do...while guarantees at least one execution.

js
let attempt = 0;

do {
  attempt += 1;
} while (attempt < 3);

Nested-loop escape with labels

Labels exist but should be rare.

js
outer:
for (const row of grid) {
  for (const cell of row) {
    if (cell === target) {
      break outer;
    }
  }
}

Usually a helper function, some, or find produces clearer code. Learn labels so you can read them, not so you can force them into every solution.

Mistakes and Debugging

  • Infinite loop: the condition remains true because the update is missing, moves the wrong direction, or updates another variable.
  • Off-by-one: index <= items.length visits one invalid index. Use < items.length.
  • Starting array traversal at 1: index 0 is the first item.
  • Resetting an accumulator inside the loop: initialize it once before the loop.
  • Using const for an accumulator/counter: use let because reassignment is intentional.
  • Mutating loop bounds unexpectedly: avoid changing array length while traversing it in beginner code.
  • continue before a while update: this can skip progress and create an infinite loop. Update before continuing or choose a for loop.
  • Overusing nested loops: estimate body executions by multiplying iteration counts.

If a page freezes, stop script execution or close the tab. Then inspect initializer, condition, and update on paper. Log the counter for a small input, but do not flood the console with an unbounded loop.

Test loops with an empty array, a one-element array, and a typical multi-element array. Empty input proves the body can run zero times safely. One element exposes incorrect starting indexes. Multiple elements checks updates and accumulation. For stop/skip logic, include a case where the sentinel is first, middle, last, and absent. These small test sets reveal control-flow errors more clearly than one large list.

Best Practices

  • Use let for counters and accumulators; use const for current values that are not rebound.
  • Use descriptive names such as index, total, and reading.
  • Traverse arrays with index < array.length.
  • Keep loop bodies small and move invariant calculations outside.
  • Validate empty arrays before calculations that require a first element or division by length.
  • Prefer for...of when the index is unnecessary.
  • Use break for a genuine stop and continue for a genuine skip, not as substitutes for clear structure.
  • Never intentionally create an infinite loop in browser practice.

Tiered Exercises

Core

Use a for loop to print numbers 1-10 and calculate their total. Then use a while loop to count down from 5 to 1.

Practice

Given [3, 10, 7, 12, 5], calculate total, count values greater than 6, and find the largest value using one loop.

Professional Extension

Given [4, -2, 9, -1, 0, 7], skip negatives, stop at zero, and total only values processed before the stop. Log each accepted value and final total.

Complete Solutions

js
let total = 0;
for (let number = 1; number <= 10; number += 1) {
  console.log(number);
  total += number;
}
console.log("Total:", total); // 55

let countdown = 5;
while (countdown >= 1) {
  console.log(countdown);
  countdown -= 1;
}
js
const values = [3, 10, 7, 12, 5];
let total = 0;
let greaterThanSix = 0;
let largest = values[0];

for (const value of values) {
  total += value;
  if (value > 6) {
    greaterThanSix += 1;
  }
  if (value > largest) {
    largest = value;
  }
}

console.log(total, greaterThanSix, largest); // 37 3 12
js
const values = [4, -2, 9, -1, 0, 7];
let total = 0;

for (const value of values) {
  if (value === 0) {
    break;
  }
  if (value < 0) {
    continue;
  }
  console.log("Accepted:", value);
  total += value;
}

console.log("Total:", total); // 13

Recap and Exit Questions

Loops repeat controlled work. for gathers setup, continuation, and update; while emphasizes a state condition. Accumulators summarize values, while break stops and continue skips. Reliable loops always make progress toward termination.

  1. Name the four moving parts of a for loop.
  2. Why is < array.length the normal array boundary?
  3. How do break and continue differ?
  4. What creates an infinite loop?
  5. When is for...of preferable?

Official References

References checked 2026-08-24.