ReviseAlgo Logo

Arrays & Iterables

forEach vs map vs for...of

Master JavaScript iteration patterns. Contrast forEach, map, and for...of in terms of return values, control flow, and performance.

Last Updated: July 15, 2026 10 min read

1. Introduction

JavaScript provides multiple ways to iterate over arrays and collections. Choosing between forEach, map, and for...of depends on whether you need to transform values, execute side effects, or control loop execution.

2. Why It Matters

Using the wrong loop pattern can lead to performance issues or logic bugs. For example, using map when you don't need a return value creates unnecessary objects in memory, while trying to break out of a forEach loop early fails because forEach does not support control flow statements.

3. Real-World Analogy

Think of a Warehouse Logistics System:

  • forEach (Stamping Packages): A worker stamps shipping labels onto packages in place. The task is performed on each item, but no new packages are created.
  • map (Repackaging Line): A worker takes items from original boxes, places them into new, branded boxes, and lines them up on a new belt. You end up with a new set of boxes.
  • for...of (Custom Sorting): A supervisor walks down a line of packages. If they find a damaged package, they stop the line immediately to inspect it, before resuming the walk.

4. Comparison Matrix

Iteration Pattern Return Value Supports break/continue? Supports async/await? Primary Use Case
for...of None Yes Yes (runs sequentially) Custom loops with control flow requirements
forEach undefined No No (does not wait for async tasks) Executing side effects on elements in place
map New array No No Transforming array elements into a new structure

5. How It Works

Let's look at the differences in code:

1. for...of Loop:

Iterates over iterable objects (including arrays, sets, and maps). It supports control flow statements like break, continue, and return.

2. forEach Loop:

Executes a callback function for each element. You cannot break or exit a forEach loop early; it always runs for all elements.

3. map Loop:

Transforms each element using a callback function, returning the result values in a new array of the same length.

6. Practical Example

This script shows why using for...of is necessary when running sequential asynchronous database requests:

7. Common Mistakes

  • Using map instead of forEach: Using map when you don't need the returned array wastes memory because the engine still allocates a new array. Use forEach or for...of instead.
  • Trying to use break inside forEach: Writing break or continue statements inside a forEach callback throws a SyntaxError.

8. Quick Quiz

Q1: Which iteration pattern supports early loop termination using the break keyword?

A) forEach

B) for...of

Answer: B — for...of supports all standard loop control flow statements, including break and continue.

9. Scenario-Based Challenge

The Search Term Interrupter:

You write a user database search function: findMatch(users, targetId). If a match is found, log it and exit immediately to save processing power. Explain why using for...of is better than using forEach for this task.

10. Debugging Exercise

Identify and fix the async loop execution bug below:

async function fetchUrls(urls) {
  const data = [];

// Bug: forEach does not await async callback processes! urls.forEach(async (url) => { const res = await fetch(url); data.push(await res.json()); });

return data; // returns empty array immediately before fetch runs!

View Solution

Diagnosis: forEach executes the callback function for each element but does not wait for asynchronous operations to complete. It returns control immediately, so the function returns the empty data array before the fetch requests finish.

Fix: Use a for...of loop to await each iteration sequentially, or use Promise.all with map for parallel requests:

// Option 1: Parallel fetches using Promise.all & map
async function fetchUrls(urls) {
  const promises = urls.map(async (url) => {
    const res = await fetch(url);
    return res.json();
  });
  return Promise.all(promises);
}

11. Interview Questions

🟢 Q1: Can you exit a forEach loop early? What happens if you throw an error inside the callback?

Answer: No, you cannot exit a forEach loop early using standard control flow statements like break or return. Throwing an error inside the callback stops the loop, but it also crashes the current execution context unless wrapped in a try...catch block. If you need to exit a loop early, use a for...of loop or array search methods like some() or find().

12. Production Considerations

  • Map vs forEach: Always use map when you are transforming data to create a new array. Use forEach or for...of only when you are executing side effects (like updating global state, logging, or saving to a database).