JavaScript forEach: What Most Developers Do Wrong 😱

Pablo AballePablo Aballe
3 min read

When working with JavaScript arrays, one method seems to be universally popular: forEach. But is it really the best choice for every situation?


1. The Hidden Problem: Modifying Arrays with forEach 🛑

forEach is often used for simple iteration, but many developers mistakenly think it can be used to modify arrays directly. Unfortunately, it doesn’t return anything, so it can lead to unintentional issues.

Mistake: Using forEach to modify an array in place.
Solution: Use map() for transformations.

let arr = [1, 2, 3];
arr.forEach(item => item * 2); // Doesn't modify arr
console.log(arr); // [1, 2, 3]

Correct way:

let arr = [1, 2, 3];
arr = arr.map(item => item * 2); // Modifies arr
console.log(arr); // [2, 4, 6]

2. Async/await with forEach: Not the Best Idea 🕑

Many developers use forEach to handle asynchronous operations, but this is problematic. forEach does not wait for promises to resolve, making it unsuitable for async operations.

Mistake: Using async/await inside forEach.
Solution: Use for...of loops instead.

const fetchData = async () => {
  let arr = [1, 2, 3];
  arr.forEach(async (item) => {
    const data = await fetch(`https://api.example.com/data/${item}`);
    console.log(await data.json());
  });
};

This leads to unpredictable behavior. Instead, use for…of for proper async handling.

const fetchData = async () => {
  let arr = [1, 2, 3];
  for (const item of arr) {
    const data = await fetch(`https://api.example.com/data/${item}`);
    console.log(await data.json());
  }
};

3. Chaining Methods After forEach is Impossible ❌

Unlike map or filter, you can’t chain methods after forEach because it doesn’t return a new array. This often leads developers to use forEach inappropriately when they actually need map.

Mistake: Trying to chain methods after forEach.
Solution: Use map() or filter() instead.

let arr = [1, 2, 3];
arr.forEach(item => item * 2).map(x => x + 1); // Error: forEach doesn't return a value

Correct way:

let arr = [1, 2, 3];
let result = arr.map(item => item * 2).map(x => x + 1); // This works!
console.log(result); // [3, 5, 7]

4. Performance Concerns ⚡

forEach is convenient, but it can be less efficient than traditional for loops. When working with large arrays, performance can suffer.

A study on JavaScript performance (from JSPerf) found that traditional for loops outperform forEach by approximately 77% in execution speed for large arrays. In testing, the forEach loop managed around 122,225 operations per second with a margin of error of ±7.08%, whereas the traditional for loop achieved 523,767 operations per second with a margin of error of ±9.70%, making it the clear choice for performance-intensive applications.

📚 JSPerf — Performance Benchmarks

This shows that while forEach is a clean and convenient way to loop through arrays, it can be less efficient for large data sets. If performance is critical, you may want to consider traditional loops for faster execution.

For large arrays, a regular for loop may save valuable processing time.


Conclusion 🏁

In summary, while forEach is a useful tool, it's important to use it wisely. Here’s a recap of the mistakes and solutions:

  • Don’t use forEach to modify arrays – Use map instead.

  • Avoid async/await inside forEach – Opt for for...of loops to handle asynchronous operations.

  • Don’t try to chain methods after forEach – Use map, filter, and other array methods for transformations.

  • Watch out for performance issues — In performance-critical code, a traditional for loop can be more efficient.

By understanding these common pitfalls and applying the right methods for the job, you can write cleaner, more efficient JavaScript code.

Happy coding, and may your arrays never be the same! 😎✨

1
Subscribe to my newsletter

Read articles from Pablo Aballe directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pablo Aballe
Pablo Aballe