Array.forEach() in JavaScript: walking an array in order to act

forEach calls a function on each item and hands back nothing: what it forbids, the asynchronous waiting trap and when for...of is better.
3 min read
Believemy logo

Walking an array to do something with each item, writing a log line, sending a message, refreshing the display: that is the one and only use of forEach.

It builds nothing and returns nothing. That is both its simplicity and its limit.


Definition

forEach is an Array method that calls a function on each item, in order, and hands back undefined. Whatever the function returns is ignored.

JAVASCRIPT
const items = ["keyboard", "mouse"];

const result = items.forEach((a, i) => console.log(i, a));
// 0 keyboard
// 1 mouse

console.log(result);   // undefined

That return value rules out any chaining. Writing items.forEach(...).filter(...) throws a TypeError, since the method is then called on undefined. A chain of steps therefore goes through Array.map() and Array.filter().


What it cannot do

break and continue mean nothing inside it: they belong to loops, not to functions. A return in the body only leaves the current pass, exactly like a continue.

JAVASCRIPT
// Leaving early calls for a real loop
for (const n of [1, 2, 3]) {
  if (n === 2) break;
  console.log(n);   // 1
}

When stopping early is precisely the goal, two methods do it on their own: Array.some() halts on the first success, Array.find() hands back the item found and ends the walk.


The waiting trap

An async function returns a Promise, and forEach throws away whatever the function returns. So it never waits for it.

JAVASCRIPT
const wait = (ms) => new Promise((ok) => setTimeout(ok, ms));

async function send(ids) {
  ids.forEach(async (id) => {
    await wait(10);
    console.log("sent", id);
  });
  console.log("done");   // prints BEFORE the sends
}

The "done" line comes out first, and an error raised inside a send travels nowhere. To wait for real, use an of loop with await, or Promise.all over a Array.map() when the sends are independent.


Frequently asked questions

Question

forEach or for...of?

The for...of loop accepts break, continue and await, which makes it the safest default. forEach keeps the edge in brevity on a short action, inside a chain where a functional style is worth holding.

Question

Does it visit the empty slots of an array?

No, it skips them. On [1, , 3] the function is called at positions 0 and 2 only, and the middle slot is ignored without any warning. Such sparse arrays are rare but appear after a delete or an assignment past the end.

Question

Can the array be changed during the walk?

Technically yes, but the number of passes is fixed at the start: items appended along the way are never visited, and a removal shifts the following ones, which then get skipped. Build a new array instead.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.