Iteration and array transformation · Lesson 29 of 77 · concept

Repeating work with for and while

About 55 minutes.

By the end of this lesson you can

  • Read a for loop header and say exactly how many times its body will run.
  • Write a counting loop that visits every element of an array by position.
  • Choose while when you cannot know the number of repetitions in advance.
  • Use break to leave a loop early and continue to skip one pass.
  • Recognise the off-by-one bug and the loop that never ends.

The problem a loop solves

Why it matters

Suppose you have four test scores and you want their total. With what you already know you could write it out by hand: take the first score, add the second, add the third, add the fourth. That works. Now suppose there are four hundred scores, or that you do not know how many there are until the program runs. Writing it out by hand stops being possible, and the version you already wrote is wrong the moment someone adds a fifth score.

A loop is the tool for that situation. It lets you write the repeated step exactly once and tell the computer how many times to perform it. The step is written once, so there is one place to fix when it is wrong — which is the real reason loops matter. Copy-pasted work has to be corrected everywhere it was pasted.

This lesson covers the two oldest and most general loops in JavaScript: for and while. Later lessons in this module replace many of these loops with shorter, clearer methods. You still need this lesson first, because those methods are built on exactly this idea, and because a plain loop remains the right answer often enough that you should be able to write one without thinking about it.

A finger moving down a list

An analogy

Picture a paper shopping list and your finger resting on the first line. You read the line your finger is on, do something about it, then move your finger down one line. When your finger goes past the last line, you stop.

That is the whole mechanism. Three things are moving: where your finger is, what you do at each line, and the rule that tells you when to stop. Every counting loop you will ever write is those same three things, and when a loop misbehaves it is almost always because one of the three is wrong — the finger starts in the wrong place, moves the wrong way, or the stopping rule lets it run one line too far.

The three parts of a for header

Explanation

A for loop puts those three things on one line, separated by semicolons: for (initialization; condition; afterthought) followed by a block. Read it left to right as: start here; keep going while this is true; do this after each pass.

The order the engine uses is worth memorising, because it explains every result you will ever see. The initialization runs once, before anything else. Then the condition is evaluated; if it is truthy the block runs, and if it is falsy the loop is over and the program continues after it. After the block finishes, the afterthought runs, and then the condition is evaluated again. Notice what that means: the condition is checked before the first pass, so a loop whose condition starts out false runs its body zero times.

Declaring the counter with let inside the header keeps it local to the loop — the name does not exist after the loop ends. That is usually what you want. It also means each pass of the loop gets its own copy of that variable, which will matter when you combine loops with functions later on.

Reading an array by position

Explanation

Array positions start at 0, so the last position of an array is always its length minus one. A three-item array has positions 0, 1 and 2, and its length is 3. Reading position 3 is not an error in JavaScript — it quietly gives you undefined, which is exactly why this class of bug survives long enough to reach a user.

That is why the standard counting loop over an array is written with a strictly-less-than condition: start the counter at 0 and keep going while it is less than the length. The counter then takes the values 0, 1 and 2 for a three-item array and stops before reaching 3. If you write less-than-or-equal instead, the loop takes one extra pass and reads a position that is not there.

while: when you cannot count in advance

Explanation

A for loop suits work you can count before you start: once per array element, ten times, however many times. Some work cannot be counted in advance. How many times must you halve a number before it drops below a hundred? You do not know until you have done it.

while takes only a condition. It evaluates the condition, runs the block if the condition is truthy, and repeats. There is no counter unless you make one, and nothing changes between passes unless your own code changes it. That is the whole difference: a for header promises to move something after every pass, and a while loop promises nothing.

There is a close relative, do...while, that runs its block once before testing the condition, so its body always runs at least once. It is rare in practice. Reach for while first, and only use do...while when the first pass genuinely must happen no matter what the condition says.

Leaving early, and skipping one pass

Explanation

Two keywords change a loop's flow from inside its body. break ends the loop immediately: no further passes, no further condition checks, execution resumes after the loop. Use it when you have found what you were looking for and the remaining work is pointless.

continue is narrower. It abandons the rest of the current pass and moves on to the next one. In a for loop the afterthought still runs before the next condition check, so the counter still advances. In a while loop there is no afterthought, so continue jumps straight back to the condition — and if the thing that was supposed to change lived after the continue, nothing changes and the loop runs forever. That is the single most common way a while loop hangs.

The two bugs everybody writes first

A common mistake

Off by one. The loop runs one pass too many or one too few, usually because the condition used less-than-or-equal where it needed less-than. The symptom for an array is an undefined appearing where you expected a value, and any arithmetic you then do with it produces NaN. When a loop over an array produces one bad result at the very end, check the condition first.

The loop that never ends. The condition never becomes falsy, so the program hangs. The two usual causes are forgetting to change the variable the condition tests, and changing it in the wrong direction. In this product the run pad has a wall-clock deadline and will stop a runaway loop and tell you it timed out, so you cannot lock up the page — but the fix is always the same: find the variable the condition depends on and make sure something in the body moves it toward the exit.

A habit that prevents both: before you run a new loop, say out loud what the counter is on the first pass, what it is on the last pass, and what makes the condition finally fail. If you cannot answer all three, the loop is not finished.

The counter is a position, not the value

A mental model

Beginners often read i as if it were the item. It is not. It is a position — a number that says where to look. The item is what you get when you use that position to index the array. Keeping those two apart in your head fixes a surprising number of bugs, because it makes it obvious that comparing i to a name or adding i to a total is nonsense.

The next lesson introduces a loop that hands you the item directly and never mentions positions at all. It exists precisely because most loops do not actually care where an item sits, only what it is.

Recap

Recap

A for header holds three things: where to start, when to keep going, and what to do after each pass. The condition is checked before every pass, including the first. A counting loop over an array starts at 0 and runs while the counter is less than the length. while takes only a condition and repeats until you make that condition false yourself. break leaves the loop; continue skips the rest of the current pass. The two bugs to expect are the extra pass at the end and the loop that never exits.

Worked examples

Every output below was produced by actually running the code in the same sandbox your exercises run in — it is not a prediction.

Adding up an array with a counting loop

The canonical counting loop: a variable outside the loop accumulates a result, and the loop visits every position exactly once. Watch how the counter is used only to look values up.

1const scores = [12, 7, 20, 3];2let total = 0;3 4for (let i = 0; i < scores.length; i += 1) {5  total = total + scores[i];6}7 8console.log(total);
  • line 1

    The data. Four values, at positions 0, 1, 2 and 3.

  • line 2

    The accumulator lives OUTSIDE the loop, or it would be reset to 0 on every pass. It starts at 0 because adding 0 to something leaves it unchanged.

  • line 4

    Start at position 0; keep going while the position is less than 4; add 1 to the position after each pass. So i is 0, 1, 2, 3 — and the loop stops before 4.

  • line 5

    scores[i] is the value AT that position. On the third pass i is 2 and scores[i] is 20.

  • line 8

    Printed after the loop has finished, not inside it.

What it prints

42

A loop whose length you cannot know in advance

Nothing here can be counted up front: the answer is how many halvings it takes. Note that the loop variables are set up before the loop and changed inside it — the while itself promises nothing.

1let population = 1000;2let years = 0;3 4while (population > 100) {5  population = population / 2;6  years = years + 1;7}8 9console.log(years);10console.log(population);
  • line 4

    The condition is checked before every pass. 1000 > 100 is true, so the body runs.

  • line 5

    This is the line that eventually makes the condition false. A while loop with no such line runs forever.

  • line 10

    62.5, not 100 — the loop stops on the first pass where the value has already gone under the limit.

What it prints

462.5

break and continue side by side

One loop using both keywords. continue skips the rest of this pass only; break abandons the loop entirely, so the values after it are never even looked at.

1const readings = [3, -1, 8, 0, 5, -4, 9];2let counted = 0;3 4for (let i = 0; i < readings.length; i += 1) {5  if (readings[i] < 0) {6    continue;7  }8  if (readings[i] === 0) {9    break;10  }11  counted = counted + 1;12}13 14console.log(counted);
  • line 6

    Skip this pass. i still advances, because a for loop runs its afterthought before the next check.

  • line 9

    Stop the loop dead. 5, -4 and 9 are never examined at all.

  • line 14

    3 and 8 were counted; -1 was skipped; 0 ended the loop. So the answer is 2.

What it prints

2

Check yourself

Not scored, not stored. Getting one wrong is the useful part.

How many times does the body of for (let i = 0; i < 4; i += 1) { ... } run?

This loop uses <= where it should use <. Exactly what will the run pad print, and why is the last line what it is?

const items = ["a", "b", "c"];for (let i = 0; i <= items.length; i += 1) {  console.log(items[i]);}

A while loop increments its counter on the last line of the body, and an if near the top of the body calls continue. What happens?

Write it yourself

Exercise · intro · 6 tests

Add up every number in an array

Write a function called total that takes an array of numbers and returns their sum, using a for loop. An empty array has a total of 0. The function must not change the array it was given — read from it, do not write to it.

What your code must do

total(numbers) returns a single number: the sum of every element, in any order (addition does not care). total([]) is 0, never undefined. The array passed in still holds exactly the same values after the call.

Define total at the top level of your code — the tests call it by name.

Runs on your device in a sandbox with no network and no access to this page.

Exercise · core · 6 tests

Count the halvings

Write a function called stepsToReach that takes two positive numbers, start and limit, and repeatedly halves start until it is less than or equal to limit. Return how many halvings that took. If start is already less than or equal to limit, no halving is needed and the answer is 0. You may assume both arguments are greater than 0. This is a job for while, not for: you cannot know the number of passes before you begin.

What your code must do

stepsToReach(start, limit) returns a whole number, counting one for each halving performed. stepsToReach(1000, 100) is 4, because 1000 becomes 500, 250, 125 and then 62.5, which is the first value at or below 100. stepsToReach(100, 100) is 0.

Define stepsToReach at the top level of your code — the tests call it by name.

Runs on your device in a sandbox with no network and no access to this page.

Worth remembering

  • In what order does a for loop evaluate its three header parts?

    Initialization once, then: condition, body, afterthought, condition, body, afterthought… The condition is checked before every pass, including the first, so a loop whose condition starts false runs zero times.

  • Why does a loop over an array use i < array.length rather than i <= array.length?

    Positions start at 0, so the last one is length minus one. <= takes one extra pass and reads a position that does not exist, which gives undefined instead of an error.

  • break versus continue

    break ends the loop entirely and execution resumes after it. continue abandons only the current pass. In a for loop the afterthought still runs after a continue; in a while loop nothing runs, which is how continue causes infinite loops.

Check this lesson against the source

We wrote the explanation; we did not invent the facts. This is the page that backs them.

MDN — for statement

Check there: The order of evaluation: initialization runs once, the condition is tested before each iteration, the body runs when it is truthy, and the afterthought runs after each iteration.

MDN — while statement

Check there: while evaluates its condition before executing the statement.

MDN — break statement

Check there: break terminates the enclosing loop and transfers control to the statement after it.

MDN — continue statement

Check there: continue terminates the current iteration only; in a for loop the update expression still runs.

Prefer to read the source in a structured breakdown? Turn this doc into a breakdown

0 of 2 exercises in this lesson solved on this device

Consent version 2026-07-31.1

Cookie preferences