Photo by chansu shin on Unsplash

On this page

This chapter follows Control flow in JavaScript.

for, while, and do-while

The C-style for (init; test; update) loop is unchanged. while prechecks; do...while runs at least once.

classic-loops.js
for (let i = 0; i < items.length; i++) {
process(items[i]);
}
let n = 0;
while (n < 10) n++;
do {
readChunk();
} while (hasMore);

Prefer let in the init clause so the index is block-scoped per iteration when using modern style.

for-of versus for-in

for...of iterates values of iterable objects (arrays, strings, Map, Set, generators, most DOM collections). for...in enumerates enumerable string keys on an object and its prototype chain—wrong for dense arrays and a security footgun on plain objects.

for-of-in.js
const ids = [10, 20, 30];
for (const id of ids) console.log(id); // 10, 20, 30
const obj = { a: 1, b: 2 };
for (const key in obj) console.log(key, obj[key]); // own + inherited enumerable keys

Use Object.keys(obj), Object.entries(obj), or for...of over a Map when you need predictable iteration.

break and continue

Unlabeled break exits the innermost loop or switch. continue skips to the next iteration of the innermost loop. Labelled forms are described in the control-flow chapter.

break-continue.js
for (const row of matrix) {
if (row.every((cell) => cell === 0)) continue;
if (row.some((cell) => cell < 0)) break;
render(row);
}

The var closure trap

var is function-scoped, not per-iteration. A classic interview bug: scheduling callbacks in a loop with var.

var-closure.js
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Logs 3, 3, 3
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0);
}
// Logs 0, 1, 2

let and const in a for loop head get a new binding per iteration. With var, capture the value with an IIFE or forEach if you cannot use let.

for-await-of

for await...of consumes async iterables (streams, paginated APIs wrapped as async generators). It must appear inside an async function or top-level module context that allows await.

for-await.js
async function drain(readable) {
for await (const chunk of readable) {
process(chunk);
}
}

Array methods versus loops

.forEach, .map, and .filter are not loops in the grammar sense—they are function calls and cannot use break/continue on an outer loop. Use a for...of when you need early exit or await inside the body (unless you use Promise.all with map).

Destructuring in loop heads appears in Destructuring and spread.

Next: Functions in JavaScript.

Search articles

Type a word to search published articles.

Open the search page