How to iterate over an array with a loop?
Short answer
- Need an index, step control, break/continue: the classic for.
- Only need the values, readability, and the ability to break: for...of.
- Just run an action for every element with no need to break: forEach.
- Need a new array/value: map, filter, reduce, some/every, find.
- Sequential async traversal: for...of + await. Parallel: Promise.all with map.
- Do not use for...in on arrays (it is for objects and can walk extra properties).
Detailed breakdown
1) The indexed for, maximum control
Fits when you need an index, a step, an early exit, skipped iterations, and maximum performance on hot paths.
const arr = [10, 20, 30, 40];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 30) continue; // skip 30
if (arr[i] > 35) break; // stop the loop
console.log(i, arr[i]); // index and value
}2) for...of, a convenient walk over values
Simple syntax for values, supports break/continue/return from the enclosing function. For indices, use arr.entries().
const arr = ['a', 'b', 'c'];
for (const v of arr) {
if (v === 'b') continue; // skip
console.log(v);
}
// Index + value via entries()
for (const [i, v] of arr.entries()) {
console.log(i, v);
}3) Array.prototype.forEach, no breaking out
Runs a function for every element, but there is no break/continue; return only ends the callback. For an early exit, use for/for...of.
const arr = [1, 2, 3];
arr.forEach((value, index) => {
// there is NO way to stop the whole forEach early
console.log(index, value);
});4) while / do...while, when the condition comes first
Used when the iterations are controlled by a condition rather than the array's length (for example, reading from a queue).
const queue = [1, 2, 3];
while (queue.length) {
const item = queue.shift();
console.log(item);
}
do {
// runs at least once
} while (false);5) for...in, not for arrays
Iterates over an object's enumerable keys, including inherited and string keys. For arrays it can give an unexpected order and "extra" properties.
const arr = [10, 20];
arr.extra = 42; // added a property
for (const k in arr) {
console.log(k); // '0', '1', 'extra', not what you expected
}
// Use for, for...of, or array methods instead.Functional methods: map / filter / reduce / some / every / find
Ideal when you need a new array/value built from the old one. They do not modify the source array (except for rare cases with mutations inside the callback).
const users = [
{ id: 1, name: 'Ann', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Cat', active: true },
];
const activeNames = users
.filter(u => u.active) // keep the active ones
.map(u => u.name); // take the names
const hasInactive = users.some(u => !u.active); // true/false
const allActive = users.every(u => u.active); // true/false
const byId = users.reduce((acc, u) => {
acc[u.id] = u; // accumulate into an object
return acc;
}, {});
const firstInactive = users.find(u => !u.active); // the first matchIndex + value
If you need both the index and the value, use arr.entries() with for...of, or the second callback argument in forEach/map/filter.
const arr = ['x', 'y', 'z'];
for (const [i, v] of arr.entries()) {
console.log(i, v);
}
arr.forEach((v, i) => console.log(i, v));Breaking out and skipping iterations
break/continue work with for/for...of/while. They are not available in forEach and the array methods (use conditional branches or other constructs instead).
const arr = [1, 2, 3, 4, 5];
for (const n of arr) {
if (n % 2 === 0) continue; // skip even numbers
if (n > 4) break; // stop at 5
console.log(n);
}Async traversals
For sequential async operations, use for...of + await. For parallel execution, use map -> Promise.all. Do not use await inside forEach; it does not wait.
// Sequential
async function processSequential(urls) {
for (const url of urls) {
const res = await fetch(url);
console.log(url, res.status);
}
}
// Parallel
async function processParallel(urls) {
const responses = await Promise.all(urls.map(url => fetch(url)));
responses.forEach((res, i) => console.log(urls[i], res.status));
}
// Anti-pattern: await inside forEach
async function bad(urls) {
urls.forEach(async (url) => {
const res = await fetch(url); // does not wait for all of them
console.log(res.status);
});
// The function returns before all the fetches finish
}Performance and readability: key points
- On hot paths the classic for is usually a bit faster, but the difference is rarely critical.
- Pick the most readable option that fits the task (map/filter for transformations, for...of for a simple walk).
- Avoid mutating the array while iterating over it (push/shift on the source array) unless that is required.
Selection cheat sheet
- Need a new array from an old one: map/filter/flatMap.
- Need to accumulate a single value (sum, object, map): reduce.
- Find/check: find/some/every.
- A simple walk over values with the ability to break: for...of.
- Index, step, complex conditions, performance: the classic for.
- Sequential async: for...of + await.
- Parallel async: Promise.all + map.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.