Q33 of 40 · JavaScript
What is the difference between `for...of`, `for...in`, and `forEach()`, and when should each be used?
Short answer
Short answer: `for...of` iterates over iterable values (arrays, strings, Maps, Sets, generators) using the iterator protocol. `for...in` iterates over enumerable string-keyed properties including inherited ones — generally avoid on arrays. `forEach` is an Array method for side effects with no early-exit mechanism.
Detail
These three constructs look similar but operate at very different levels of the language.
for...of: Uses the Symbol.iterator protocol. Works on any iterable: arrays, strings, Maps, Sets, NodeLists, generators, and custom objects that implement Symbol.iterator. Supports break, continue, return, and await inside for await...of. This is the modern default for iterating values.
for...in: Iterates over all enumerable string-keyed properties of an object, including inherited properties from the prototype chain. On arrays, it iterates indices as strings plus any enumerable prototype properties — this is why using for...in on arrays is risky. Designed for plain object property enumeration.
forEach(): An Array (and Map/Set) prototype method. Synchronous. Always iterates every element — you cannot break early with break (throw an exception to escape, which is ugly). Cannot be used with await in a useful way — use for...of for async iteration.
In test automation: for...of with await is the correct pattern for sequential async iteration over test fixtures. for...in should be avoided on arrays; forEach is fine for synchronous side effects with no early exit.
// EXAMPLE
const arr = [10, 20, 30];
// for...of — iterates values, supports break/await
for (const val of arr) {
if (val === 20) break; // works!
console.log(val); // 10
}
// for...in — iterates keys (as strings), includes prototype!
Array.prototype.myMethod = () => {};
for (const key in arr) {
console.log(key); // "0", "1", "2", "myMethod" ← dangerous!
}
// forEach — no break, no await
arr.forEach(val => {
// break; // SyntaxError — break not allowed here
console.log(val);
});
// Async sequential iteration — for...of + await
for (const user of users) {
await db.insert(user); // sequential — each awaited
}
// Map iteration with for...of
const map = new Map([["a", 1], ["b", 2]]);
for (const [key, value] of map) { /* key-value pairs */ }