When to Use for, for of, and forEach in JavaScript
JavaScript gives you three main ways to loop over arrays. Learn when to choose classic for, for...of, or forEach based on whether you need the index, break, await, or clean syntax.
JavaScript gives you three primary ways to loop over an array: the classic for loop, the for...of loop, and the forEach method. They all get the job done, but each has distinct strengths that make it the best choice in different situations.
This article focuses on when to pick which one. For deep dives into each, see the individual guides on the classic for loop, for...of, and looping through arrays.
At a Glance
| Feature | Classic for | for...of | forEach |
|---|---|---|---|
| Values directly | Via arr[i] | Yes | Yes |
| Index access | Built-in | Via .entries() | 2nd argument |
break / continue | Yes | Yes | No |
await inside | Yes | Yes | No |
| Reverse iteration | Yes | No | No |
| Skip N items | Yes | No | No |
| Works on objects | No | No | No |
| Method chaining | No | No | Yes |
| Return value | None | None | undefined |
Decision Flow
The diagram shows the key decision points. The two features that rule out forEach are break/continue and await. If you need either, you must use a loop statement. After that, the choice between classic for and for...of depends on whether you need index-level control.
Choose Classic for When You Need the Index
The classic for loop is the only option that gives you full control over the index. Use it when:
const items = ["a", "b", "c", "d", "e"];
// Skip the first two items
for (let i = 2; i < items.length; i++) {
console.log(items[i]); // c, d, e
}
// Iterate in reverse
for (let i = items.length - 1; i >= 0; i--) {
console.log(items[i]); // e, d, c, b, a
}
// Step by 2
for (let i = 0; i < items.length; i += 2) {
console.log(items[i]); // a, c, e
}
// Modify elements in place
for (let i = 0; i < items.length; i++) {
items[i] = items[i].toUpperCase();
}When you need to start at an offset, go backward, step by intervals, or modify the array by index, the classic for loop is the clearest and most direct tool.
Choose for...of for Clean Value Iteration
for...of is the best default for most array iteration. It gives you direct access to values with clean syntax and full language feature support:
const users = [
{ name: "Alice", role: "admin" },
{ name: "Bob", role: "editor" },
{ name: "Carol", role: "viewer" },
];
// Clean value access with break
for (const user of users) {
if (user.role === "admin") {
console.log("Admin found:", user.name);
break;
}
}
// Async iteration
for (const user of users) {
const permissions = await fetchPermissions(user.id);
console.log(user.name, permissions);
}The break in the first example stops the search once the admin is found. The await in the second example processes users sequentially, waiting for each permission fetch before moving to the next. Neither is possible with forEach.
Choose forEach for Functional Pipelines
forEach shines when you are already working in a functional style, chaining array methods:
const numbers = [1, 2, 3, 4, 5, 6];
numbers
.filter((n) => n % 2 === 0) // Keep evens
.map((n) => n * 10) // Multiply by 10
.forEach((n) => { // Log results
console.log(n);
});
// Prints: 20, 40, 60forEach also reads well when you want the callback pattern and have the index available as the second argument:
["Alice", "Bob", "Carol"].forEach((name, index) => {
console.log(`${index + 1}. ${name}`);
});
// 1. Alice, 2. Bob, 3. CarolSide-by-Side: Same Task, Three Ways
Here is the same task -- logging each element -- written three ways:
const fruits = ["apple", "banana", "cherry"];
// Classic for: explicit index
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// for...of: clean, no index needed
for (const fruit of fruits) {
console.log(fruit);
}
// forEach: functional callback style
fruits.forEach((fruit) => {
console.log(fruit);
});All three print the same output. The classic for is the most verbose but gives you the index. for...of is the cleanest for value-only iteration. forEach reads naturally when you are already thinking in callbacks.
The await Trap with forEach
This is the most important practical difference. forEach does not wait for async operations:
// BUG: forEach fires all requests at once, does not wait
const ids = [1, 2, 3];
ids.forEach(async (id) => {
const data = await fetch(`/api/item/${id}`);
console.log(data); // Runs after forEach already finished
});
console.log("Done"); // Prints FIRST, before any fetch completesThe async callback makes each iteration return a promise, but forEach ignores the return value. "Done" prints immediately, and the fetches complete in the background in an unpredictable order.
// RIGHT: for...of waits for each iteration
for (const id of ids) {
const data = await fetch(`/api/item/${id}`);
console.log(data); // Prints in order, one at a time
}
console.log("Done"); // Prints LAST, after all fetches completeQuick Reference Table
| Situation | Best Choice |
|---|---|
| Need the index to modify or offset | Classic for |
| Need value only, simple iteration | for...of |
Need break or continue | Classic for or for...of |
Need await inside the loop | for...of |
| Chaining after filter/map | forEach |
| Reverse iteration | Classic for |
| Stepping by intervals | Classic for |
| Async operations in sequence | for...of |
For object iteration, none of these three apply directly -- see looping through objects in JavaScript. For the fourth loop type that works on object keys, see the for...in guide.
Rune AI
Key Insights
- Use classic for when you need the index, reverse iteration, or fine-grained control.
- Use for...of as your default for value-only iteration with break/continue/await.
- Use forEach for functional pipelines and when you prefer the callback style.
- for...of and classic for support break and continue; forEach does not.
- for...of and classic for support await; forEach does not.
Frequently Asked Questions
Is forEach faster than a for loop?
Can I chain array methods after a for loop?
Which loop should I use as a default?
Conclusion
Each loop approach has a clear strength: classic for gives you full index control, for...of gives you clean value iteration with break and await support, and forEach integrates well with functional pipelines. The right choice depends on what you need in that specific loop. Start with for...of as your default and switch when the situation calls for more control or a more functional style.
More in this topic
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.
How to Loop Through Arrays Using JS for Loops Guide
Looping through arrays is the most practical use of JavaScript for loops. Learn how to access each element by index, avoid off-by-one errors, and choose between for, for...of, and forEach.