Loops: while and for
Some work is the same thing done over and over. Print every item in a shopping cart. Add up the numbers 1 through 10. Keep asking the user for input until they finally type something valid. Writing that code out by hand, one line per repetition, would be miserable and wouldn’t scale — you rarely know in advance how many times you need to go around.
A loop is the tool for that. You describe the body of work once and hand the computer a rule for when to keep going and when to stop.
The “while” loop
The while loop is the simplest one to picture. It has a condition and a body, and it keeps running the body as long as the condition holds.
while (condition) {
// code
// — the "loop body"
}
Before each pass, JavaScript checks condition. If it’s truthy, the body runs. Then it checks again. As soon as the condition turns falsy, the loop is done and execution moves on to whatever follows it.
Here’s a loop that prints i while i is still below 3:
let i = 0;
while (i < 3) { // shows 0, then 1, then 2
alert( i );
i++;
}
Each full run through the body is called an iteration. That loop makes three of them.
Watch the machinery run one line at a time. Notice that the condition is checked before every iteration, and that the loop ends when the check finally fails — the body does not run a fourth time.
The i++ line is doing quiet but critical work. Every iteration it nudges the counter closer to the exit condition. Drop it, and i sits at 0 forever, the condition stays true, and the loop never stops.
The condition is just a boolean test
The condition doesn’t have to be a comparison. while takes whatever expression you give it, evaluates it, and converts the result to a boolean. Any truthy value keeps the loop alive; any falsy one (0, "", null, undefined, NaN, false) ends it.
So while (i != 0) can be shortened to while (i) — the number i is truthy until it hits 0:
let i = 3;
while (i) { // when i becomes 0, the condition is falsy and the loop stops
alert( i );
i--;
}
This prints 3, 2, 1. On the pass where i reaches 0, the condition while (0) is falsy, so the body is skipped and the loop ends. The shorthand is idiomatic, but only reach for it when the intent stays obvious to a reader.
The “do..while” loop
Sometimes you want the body to run at least once before the condition is ever checked. The do..while loop moves the test to the bottom:
do {
// loop body
} while (condition);
The body runs first, then the condition is checked. If it’s truthy, the body runs again, and so on. Here’s the difference in shape:
For example:
let i = 0;
do {
alert( i );
i++;
} while (i < 3);
Reach for do..while only when the body genuinely must run once no matter what — for instance, showing a prompt and then deciding whether to show it again based on the answer. Most of the time the plain while(…) {…} reads better, so prefer it by default.
The “for” loop
The for loop packs the three moving parts of a counting loop — setup, test, and update — into one compact header. It’s the workhorse loop you’ll see most often.
for (begin; condition; step) {
// ... loop body ...
}
Here it is counting from 0 up to (but not including) 3:
for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2
alert(i);
}
Each piece of the header has a distinct job:
| part | ||
|---|---|---|
| begin | let i = 0 |
Runs once, when the loop is first entered. |
| condition | i < 3 |
Checked before every iteration. When it’s false, the loop stops. |
| body | alert(i) |
Runs each time the condition passes. |
| step | i++ |
Runs after the body, at the end of every iteration. |
The order these fire in matters, so keep this picture in your head:
So begin runs once, and after that the cycle is: test the condition, and if it passes, run the body then the step. If it were unrolled into plain if statements, the earlier loop would read like this:
// for (let i = 0; i < 3; i++) alert(i)
// run begin
let i = 0
// if condition → run body and run step
if (i < 3) { alert(i); i++ }
// if condition → run body and run step
if (i < 3) { alert(i); i++ }
// if condition → run body and run step
if (i < 3) { alert(i); i++ }
// ...finished, because now i == 3
New to loops? Copy the example onto paper and trace i by hand through each pass. It cements the order faster than reading ever will.
Skipping parts
Every one of the three header parts is optional. Leave any out when you don’t need it.
Skip begin if the counter already exists:
let i = 0; // already declared and set
for (; i < 3; i++) { // no "begin" needed
alert( i ); // 0, 1, 2
}
Drop the step too, and handle the update inside the body instead:
let i = 0;
for (; i < 3;) {
alert( i++ );
}
At that point the for behaves exactly like while (i < 3) — same test, same absence of an automatic step.
Strip all three and you get a deliberate infinite loop:
for (;;) {
// repeats with no limit
}
One rule survives no matter how much you remove: the two semicolons must stay. They mark the three slots, and without them JavaScript reports a syntax error.
Breaking the loop
A loop normally ends when its condition goes falsy. But you can bail out early, from anywhere in the body, with the break directive.
This loop keeps asking for prices and adds them up. The moment the user submits an empty value or cancels, break stops it:
let total = 0;
while (true) {
let price = +prompt("Enter a price", '');
if (!price) break; // (*)
total += price;
}
alert( 'Total: ' + total );
The header condition here is literally true, so the loop would never stop on its own. The real exit lives at line (*): if price is empty (or the user cancels, giving null, which +null turns into 0), break fires and control jumps to the first line after the loop — the alert.
That pattern, while (true) plus a break where it makes sense, is the go-to when the natural stopping point isn’t at the top or bottom of the loop but somewhere in the middle. You get to decide exactly where the check happens.
Continue to the next iteration
continue is the softer cousin of break. It doesn’t end the loop — it just abandons the current iteration and jumps ahead to the next one (running the step and re-checking the condition on the way).
Use it when you’re finished with this pass and want to skip the rest of the body. This loop prints only the odd numbers:
for (let i = 0; i < 10; i++) {
// if true, skip the rest of the body this time around
if (i % 2 == 0) continue;
alert(i); // 1, then 3, 5, 7, 9
}
When i is even, continue cuts the iteration short before the alert, and the loop moves on to the next value. So only odd numbers make it to the screen.
Labels for break/continue
break and continue only affect the loop they sit in. That’s a problem when loops are nested and you want to escape all of them at once.
Here we walk a seating chart, prompting for a guest name at each spot from row 0, seat 0 up to row 2, seat 2:
for (let row = 0; row < 3; row++) {
for (let seat = 0; seat < 3; seat++) {
let guest = prompt(`Guest in row ${row}, seat ${seat}`, '');
// what if we want to jump straight to Done (below) from here?
}
}
alert('Done!');
If the user cancels a prompt, we’d like to stop everything. A plain break inside the inner loop only breaks that inner loop — the outer one keeps going and starts the next row. Not what we want.
A label solves this. It’s an identifier with a colon, placed just before a loop:
labelName: for (...) {
...
}
Then break labelName breaks out of that labeled loop, however deep you are inside it:
outer: for (let row = 0; row < 3; row++) {
for (let seat = 0; seat < 3; seat++) {
let guest = prompt(`Guest in row ${row}, seat ${seat}`, '');
// on empty input or cancel, break out of BOTH loops
if (!guest) break outer; // (*)
// do something with the guest name...
}
}
alert('Done!');
break outer scans outward for the loop tagged outer and exits it. Control leaps from line (*) past both loops, straight to alert('Done!').
The label can also sit on its own line above the loop, which some people find cleaner:
outer:
for (let i = 0; i < 3; i++) { ... }
continue takes a label too. continue outer skips to the next iteration of the labeled loop rather than the innermost one — handy for “abandon this whole row and start the next.”
Summary
Three loops, three shapes:
while (condition) {…}— checks the condition before each iteration.do {…} while (condition)— checks after each iteration, so the body always runs at least once.for (begin; condition; step) {…}— checks before each iteration, with built-in slots for setup and the per-pass update.
For a deliberate endless loop, while (true) is the usual idiom. Like any loop, it can be stopped with break.
To skip the rest of the current pass and move to the next one, use continue.
Both break and continue accept a label placed before a loop, and that label is the only clean way to make them escape a nested loop and act on an outer one.