Loops and Iteration
Repeating work without repeating yourself — `while`, `for`, `for...of`, `for...in`, and the higher-level array methods.
The second great power of control flow — after decisions — is repetition. Almost every interesting program needs to do the same kind of thing many times: process every file in a folder, every row in a table, every pixel on a screen, every customer in a database. That repetition is called iteration, and the syntactic tools for it are called loops.
JavaScript has several kinds of loop. We will learn each one and, just as importantly, when to use which.
The while loop
The simplest loop. While the condition is truthy, run the body. Then check the condition again.
while (condition) {
// body
}Step-by-step trace of what the runtime does:
| Step | n before | condition | action |
|---|---|---|---|
| 1 | 1 | 1 <= 5 is true | print, n becomes 2 |
| 2 | 2 | true | print, n becomes 3 |
| 3 | 3 | true | print, n becomes 4 |
| 4 | 4 | true | print, n becomes 5 |
| 5 | 5 | true | print, n becomes 6 |
| 6 | 6 | 6 <= 5 is false | leave the loop |
The most important habit: make sure something in the body changes the condition, or your loop will run forever. An infinite loop that you cannot interrupt is one of the few things in JavaScript that will make your tab unresponsive.
The for loop
Often you want to do something N times, or walk an index from
some start to some end. The for loop is while with three slots
pulled out so they sit together at the top:
for (init; condition; update) {
// body
}- init runs once, before the loop starts.
- condition is checked before each iteration.
- update runs at the end of each iteration.
That i++ is a compact way to write i = i + 1. Combined with the
for loop's three slots, it makes counting loops short and
readable.
The two loops you just ran are exactly equivalent to writing them
with while:
let i = 0;
while (i < 5) {
console.log("i =", i);
i++;
}Same behaviour; just less compactly written.
for...of: walk every element
When you have an array (or any iterable — strings, Sets, Maps,
etc.) and you want to do something for each element, for...of is
usually the clearest choice. You don't have to manage an index at
all.
If you do need the index alongside the element, use
array.entries():
That [index, color] is destructuring, which we have not
formally introduced yet. Treat it as a convenient way to say "give
me each pair as two named variables". We will see destructuring
properly in the objects chapter.
for...in: walk an object's keys
for...in walks the keys of an object — useful when you want
to look at every named property. It is not appropriate for arrays
(use for...of for those).
We will look at objects in detail in their own chapter. For now,
remember the shape: for (const key in object).
break and continue
Inside any loop, two special statements let you bail out or skip ahead:
breakexits the loop entirely.continueskips the rest of the current iteration and starts the next.
Use these sparingly. Heavy use of break/continue is often a
sign that the loop is doing too many things at once and could be
split into smaller helpers.
The "loop and accumulate" pattern, revisited
We saw this in the Computational thinking chapter. It is the single most common shape of loop in real code: start with a blank result, walk a list, update the result.
Notice that each example is the same pattern: initialise; loop; update. Once you see this shape, you see it everywhere.
Higher-level alternatives: forEach, map, filter, reduce
For the very common pattern of "do something with every element of an array", arrays come with built-in methods that often read better than a hand-written loop. We will dedicate an entire later chapter to these, but here is a small taste:
These are the functional style of iteration: instead of writing the loop, you describe what you want done with each element, and JavaScript runs the loop for you.
When learning, write the explicit for loop first; then, once you
are comfortable, switch to map/filter/reduce where they make
the intent clearer.
Nested loops
A loop inside a loop is called a nested loop. The inner loop runs to completion for each iteration of the outer loop. This is how you generate combinations, walk a grid, or compare every item to every other item.
Be mindful of cost: nesting an N-element loop inside another N-element loop runs the inner body N×N times. For N=10 that's 100 — fine. For N=10,000 that's 100,000,000 — possibly too slow.
Beware the infinite loop
Always ask: how does this loop end? Common mistakes:
// (a) Forgetting to update the counter
let i = 0;
while (i < 5) {
console.log(i);
// Oops — forgot i++. This runs forever.
}
// (b) Updating the wrong way
for (let i = 0; i < 10; i--) {
console.log(i);
// i goes 0, -1, -2, ... forever.
}If your tab freezes when you press Run, your loop almost certainly forgot to terminate. Stop the runtime, find the loop, fix the update.
Step-by-step execution diagram
Mentally tracing a loop is a skill. Here is a flowchart for the
classic for (let i = 0; i < N; i++) { ... }:
Picture this in your head every time you write a for loop. Half
the loop bugs in the world come from forgetting where each piece
goes in this cycle.
Challenge
Write a function fizzbuzz(n) that returns an array of n strings. For positions 1 through n:
- If the position is divisible by 15, the string is
"FizzBuzz". - Otherwise, if it's divisible by 3, the string is
"Fizz". - Otherwise, if it's divisible by 5, the string is
"Buzz". - Otherwise, the string is the position number, converted to a string (e.g.
"7").
For example, fizzbuzz(5) should return ["1", "2", "Fizz", "4", "Buzz"].
Implement it with a for loop and an array you build up with .push().
Which loop is the cleanest way to do something for every element of an array, when you don't need the index?
A while loop with a manual counter
A for (let i = 0; i < arr.length; i++) loop
A for...in loop
A for...of loop: for (const item of arr) { ... }