.forEach() Method

I'm tackling the .forEach() method this week, which is an array method that can be reached for instead of a for-loop when a developer needs to loop over items in an array.

Every JavaScript developer should be familiar with the following code:

const array = [1, 2, 3, 4, 5, 6];

for (let i = 0; i <= array.length; i += 1) {
  console.log(array[i]);
};

// expected output:
// 1
// 2
// 3
// 4
// 5
// 6

The trusty for-loop is nice and performant. That's some classic code right there. It's executing the console log for each element of the array. We can do the same thing using the .forEach() method:

const array = [1, 2, 3, 4, 5, 6];

array.forEach((number) => {
  console.log(number);
});

// expected output:
// 1
// 2
// 3
// 4
// 5
// 6

.forEach() vs .map()

Easy enough, right? It just executes the callback function that gets passed on each array item. But wait, doesn't that sound like .map()? What's the difference? Let's take a look at what MDN has to say about these two methods.

.forEach(): From MDN: The .forEach() method executes a provided function once for each array element.

.map(): From MDN: The .map() method creates a new array with the results of calling a provided function on every element in the calling array.

Hmm, okay. So there's something where .map() returns a new array, but both methods are doing work on the original array, right? Maybe Jeff Lombard can clear it up in this Medium post:

.forEach() is great you need to execute a function for each individual element in an array. Good practice is that you should use .forEach() when you can’t use other array methods to accomplish your goal. I know this may sound vague, but .forEach() is a generic tool...only use it when you can’t use a more specialized tool.

Huh. You're right, Jeff, that is pretty vague.

What I've figured out is that the difference between the .forEach() method and the .map() method lies in what each of these methods returns or does not return. Brandon Morelli breaks this down nicely in this article. .map() returns a new array, populated by items that are the result of the callback function executing on each array item. .forEach() on the other hand doesn't return anything at all.

Look at the following:

const array = [1, 2, 3, 4, 5, 6];

const newArray = array.forEach((number) => {
  return number * 2;
});

console.log(newArray);
// result: undefined

newArray is undefined because .forEach() isn't returning anything at all. If you're looking for a new array where each item of the original array has had some work done on it by the callback function, you should be using the .map() method.

const array = [1, 2, 3, 4, 5, 6];

const newArray = array.map((number) => {
  return number * 2;
});

console.log(newArray);
// result: [2, 4, 6, 8, 10, 12]

The key here is that .forEach() executes its callback for each item on the original array itself, and then removes those items from memory. All of the action happens inside of the .forEach() method. Whereas .map() returns a new array, leaving the original data intact. This is a crucial distinction.

So then when would you use .forEach()?

One common real-world use case is when you have an array of data that you need to push into a database. If you don't need to modify the data further, you can just loop over the data using .forEach(), pushing each item into the database.

Another use case I've found is in working with GatsbyJS, specifically in the gatsby-node.js file. A typical Markdown-based Gatsby site will look through the specified file system for all available Markdown files, and for each Markdown file, run the createPage action. This looks something like the following:

const blogPosts = data.allMarkdownRemark.edges;
blogPosts.forEach(blogPost => {
  actions.createPage({
    path: `blog${blogPost.node.fields.slug}`,
    component: blogPostTemplate,
    context: {
      slug: blogPost.node.fields.slug,
    }
  });
});

Summary

.forEach() is simply an array method that does the work of a for-loop, which is iterating over all items in an array. An advantage that .forEach() has over a for-loop is that a for-loop typically comes with some scope pollution. That said, it's also worth noting that a for-loop executes faster than .forEach().

.forEach() doesn't return anything, instead it simply executes the provided callback function on each item in the original data, allowing for mutation of the original data. If you need to return altered data, reach for .map() instead.

See more examples and further documentation here.