Loops
JavaScript has several ways to repeat code. Picking the right one makes intent obvious — a for...of loop over an array says “iterate values,” a for...in loop says “iterate keys,” and so on.
-
forThe classic counted loop — best when you need an index, a custom step, or to iterate in reverse.
for (let i = 0; i < 3; i++) { console.log(i); // 0, 1, 2 } // Reverse iteration const fruits = ["apple", "banana", "cherry"]; for (let i = fruits.length - 1; i >= 0; i--) { console.log(fruits[i]); // "cherry", "banana", "apple" } -
whileRuns as long as a condition is true — use it when the number of iterations isn’t known ahead of time.
let attempts = 0; let success = false; while (!success && attempts < 3) { attempts++; success = attempts === 3; // pretend the 3rd attempt succeeds console.log(`Attempt ${attempts}: ${success ? "success" : "failed"}`); } -
do...whileSame as
while, but the condition is checked after the body runs — guarantees at least one execution.let n = 10; do { console.log(n); // 10 — runs once even though the condition is false n++; } while (n < 5); -
for...inIterates over an object’s enumerable property keys (as strings) — including inherited ones from the prototype chain. Meant for plain objects, not arrays.
const user = { name: "Ada", age: 36 }; for (const key in user) { console.log(key, user[key]); // "name" "Ada", "age" 36 }// Gotcha: for...in on an array iterates indices as strings, in // unspecified order, and picks up any enumerable inherited properties too const arr = ["a", "b", "c"]; for (const index in arr) { console.log(typeof index, index); // "string" "0", "string" "1", "string" "2" } // Prefer for...of (or forEach/map) for arrays instead. -
for...ofIterates over the values of any iterable — arrays, strings, Maps, Sets, generators (see generators-iterators). This is the go-to loop for arrays when you don’t need the index.
const scores = [10, 20, 30]; for (const score of scores) { console.log(score); // 10, 20, 30 } for (const char of "hi") { console.log(char); // "h", "i" } // Need the index too? Destructure entries() for (const [index, score] of scores.entries()) { console.log(index, score); // 0 10, 1 20, 2 30 } -
breakandcontinuebreakexits the loop entirely;continueskips to the next iteration.for (let i = 0; i < 5; i++) { if (i === 3) break; console.log(i); // 0, 1, 2 } for (let i = 0; i < 5; i++) { if (i % 2 === 0) continue; // skip even numbers console.log(i); // 1, 3 } -
Labeled loops
Labels let
break/continuetarget an outer loop from inside a nested one — useful for escaping nested loops in one step.outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (j === 1) continue outer; // skips to the next `i`, not just the next `j` console.log(i, j); } } // 0 0 // 1 0 // 2 0
Loops vs array iteration methods
forEach/map/filter/etc. (see higher-order-functions) are usually preferred over manual loops for arrays because they’re more declarative — but they aren’t a drop-in replacement for every case.
// forEach cannot be stopped early — break/continue don't work inside it
[1, 2, 3].forEach((n) => {
if (n === 2) break; // SyntaxError: Illegal break statement
});
// A regular for/for...of loop CAN be stopped early
for (const n of [1, 2, 3]) {
if (n === 2) break; // works fine
console.log(n); // 1
}
// await inside forEach's callback does NOT pause the outer function —
// the callback's promise is silently ignored
async function processAll(items) {
items.forEach(async (item) => {
await save(item); // fires all saves concurrently, unordered, unawaited
});
console.log("done"); // logs before any save() has actually finished
}
// for...of DOES pause correctly, awaiting each iteration in sequence
async function processAllSequentially(items) {
for (const item of items) {
await save(item); // waits for each save before moving to the next
}
console.log("done"); // logs only after every save() has finished
}
Quick guide
- Need an index or custom step/direction →
for - Unknown number of iterations, condition-driven →
while/do...while - Iterating a plain object’s keys →
for...in - Iterating an array’s/iterable’s values, with
break/continue/awaitsupport →for...of - Transforming/filtering/reducing an array declaratively, no early exit needed →
map/filter/reduce(see higher-order-functions)