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.

6 min read

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

FeatureClassic forfor...offorEach
Values directlyVia arr[i]YesYes
Index accessBuilt-inVia .entries()2nd argument
break / continueYesYesNo
await insideYesYesNo
Reverse iterationYesNoNo
Skip N itemsYesNoNo
Works on objectsNoNoNo
Method chainingNoNoYes
Return valueNoneNoneundefined

Decision Flow

Choosing for, for...of, or forEach

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:

javascriptjavascript
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:

javascriptjavascript
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:

javascriptjavascript
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, 60

forEach also reads well when you want the callback pattern and have the index available as the second argument:

javascriptjavascript
["Alice", "Bob", "Carol"].forEach((name, index) => {
  console.log(`${index + 1}. ${name}`);
});
// 1. Alice, 2. Bob, 3. Carol

Side-by-Side: Same Task, Three Ways

Here is the same task -- logging each element -- written three ways:

javascriptjavascript
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:

javascriptjavascript
// 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 completes

The 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.

javascriptjavascript
// 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 complete

Quick Reference Table

SituationBest Choice
Need the index to modify or offsetClassic for
Need value only, simple iterationfor...of
Need break or continueClassic for or for...of
Need await inside the loopfor...of
Chaining after filter/mapforEach
Reverse iterationClassic for
Stepping by intervalsClassic for
Async operations in sequencefor...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

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.
RunePowered by Rune AI

Frequently Asked Questions

Is forEach faster than a for loop?

No. The classic for loop is generally the fastest because it avoids function call overhead. But for most arrays under a few thousand items, the difference is not noticeable. Choose based on readability and feature needs, not speed.

Can I chain array methods after a for loop?

No. for and for...of are statements, not methods. If you need method chaining like .filter().map(), use array methods. If you need break, continue, or await, use a loop statement.

Which loop should I use as a default?

Start with for...of for most array iteration. It is clean, supports break/continue/await, and works on all iterables. Switch to classic for when you need the index. Use forEach for functional pipelines and when you want the callback pattern.

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.