JavaScript Loops
Pick the right loop in JavaScript with for, while, for-of, for-in, and array methods.
TL;DR
- 01Use
forandwhilewhen you need full counter control. - 02Use
for-offor arrays andfor-infor object keys. - 03Use array methods like
mapandfilterfor transformations.
Tips
- 01Reach for array methods like map and filter first for transformations, since they read more clearly than equivalent for loops.
- 02Use for...of instead of for...in on arrays, since for...in iterates keys as strings and can pick up inherited enumerable properties.
Warnings
- 01Do not modify an array with splice or push while looping, since this skips items and causes subtle bugs.
- 02Using await inside a forEach callback silently fails to pause, since forEach ignores returned promises and runs callbacks without waiting.
For and While
- JavaScript gives you three ways to loop with a condition, and each one fits a different shape of problem.
for (let i = 0; i < 5; i++) { console.log(i); } - Use a
whileloop when you do not know how many iterations are needed.let n = 0; while (n < 3) { console.log(n); n++; } - Use
do...whilewhen the body must run at least once before checking.let i = 0; do { console.log(i); i++; } while (i < 3); - Always make sure the loop condition can become false to avoid infinite loops.
- Use
breakto exit a loop early andcontinueto skip an iteration.
For-of for Arrays
- No index, no counter, no off-by-one errors —
for...ofhands you each value directly.const nums = [10, 20, 30]; for (const n of nums) console.log(n); - Works on strings, Sets, Maps, NodeLists, and any other iterable.
for (const char of "Hi") console.log(char); - Destructure inside the loop for cleaner access to object properties.
for (const { name } of users) console.log(name); - This is the cleanest loop for most array iteration needs in modern code.
- Use
entries()if you also need the index alongside the value.
For-in for Objects
for...inwalks property names, not values — a distinction that trips up developers coming fromfor...of.const user = { name: 'Ada', age: 30 }; for (const key in user) { console.log(`${key}: ${user[key]}`); }- Use bracket notation
obj[key]to read each value during the loop. - Avoid using
for...inon arrays, since it iterates keys, not values. - Add a
hasOwnPropertycheck to skip inherited properties when needed. - Prefer
Object.keys()orObject.entries()for more predictable iteration.
Async Loops
- forEach silently ignores every promise its callback returns, making it the most common source of broken async loops.
async function processAll(ids) { for (const id of ids) { const result = await fetchItem(id); console.log(result); } } - Avoid
forEachwithawait— it does not wait for each async callback to complete.// Broken: forEach ignores returned promises items.forEach(async item => { await save(item); // fires but does not block }); - Use
Promise.all()withmap()to run all async operations in parallel instead.const results = await Promise.all(ids.map(id => fetchItem(id))); - Use
for await...ofto consume an async iterable like a stream or generator.for await (const chunk of readStream()) { console.log(chunk); } - Sequential
for...ofwith await is slower but safe when order matters between items.
Nested and Control
- A plain
breakonly escapes the innermost loop — labeled breaks are the only way out of nested ones.for (let i = 0; i < 2; i++) { for (let j = 0; j < 3; j++) { console.log(`${i},${j}`); } } - Use labeled
breakto exit out of multiple levels of nested loops.outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (i === 1) break outer; } } - Use
breakto exit a search loop as soon as you find what you need. - Use
returninside array methods likeforEachto skip an iteration. - Cache
array.lengthoutside hotforloops for a small performance gain.
FAQ
for-of iterates over iterable values (arrays, strings, Sets, Maps), while for-in iterates over an object's enumerable property keys as strings. Use for-of when you want array element values and for-in when you need to walk an object's keys.
await works correctly inside for, for-of, and while loops, running each iteration sequentially. Avoid putting await inside forEach, since it ignores returned promises and the outer function will not wait. Use for-of instead.
Label the outer loop, like outer:, then call break outer inside the inner loop to exit both levels at once. Alternatively, extract the inner loop into a function and return early.
for-in enumerates all inherited enumerable properties, not just ones you defined directly. Use Object.keys(obj) to get only own enumerable keys as an array, or add an obj.hasOwnProperty(key) guard inside the loop.
Prefer map when producing a new array of the same length with transformed values, and filter when selecting a subset. Both express intent clearly. Reach for a for or for-of loop when you need to break early or accumulate a non-array result.