JavaScript Array .map() vs .forEach()

Published on 2021-10-17

When working with arrays of data, it can be a bit confusing when you should reach for map or forEach, so in this post I hope to help clear that up!

tldr: use map if you want to make transformations to the data, use forEach if you want to perform side effects.

Lets imagine we have an array of store items that we would like to work with:

const storeItems = [
  { name: 'Sunglasses', price: 15.00, memberDiscount: true},
  { name: 'Flip flops', price: 50.00, memberDiscount: true},
  { name: 'Sunscreen', price: 5.99, memberDiscount: false}
];

Mapping

Say we wanted to use this data, but we wanted to modify the items to have all their names uppercase:

const uppercaseItems = storeItems.map(item => {
  return {...item, name: item.name.toUpperCase()};
});
/*
[
  { name: 'SUNGLASSES', price: 15.00, memberDiscount: true},
  { name: 'FLIP FLOPS', price: 50.00, memberDiscount: true},
  { name: 'SUNSCREEN', price: 5.99, memberDiscount: false}
]
*/

The above function will return a new array with modified names, and it WONT update the storeItems array so that will continue to hold the initial values.

For another example, what if we wanted to modify the price based on if there is a member discount, and the person currently viewing the data is a member. We could write the following function:

const applyMemberDiscounts = (items, isMember) => {
  return items.map(item => {
    if (!item.memberDiscount || !isMember) return item;

    const price = item.price - (item.price * 0.20);
    return {...item, price};
  });
};

const discounted = applyMemberDiscounts(storeItems, true);
/*
[
  { name: 'Sunglasses', price: 12.00, memberDiscount: true},
  { name: 'Flip flops', price: 40.00, memberDiscount: true},
  { name: 'Sunscreen', price: 5.99, memberDiscount: false}
]
*/

For a final example, I'll talk about how I use map when rendering React components. If I had some component, <StoreItem> that took all the values and made them look pretty, I would display them by building all the components and storing them in a new array, then later in the JSX I can just pass the array as children.

const comps = storeItems.map(item => <StoreItem {...item} />)

...

// In component return
return (
  <div>
    {comps}
  </div>
)

You can probably start to imagine how you would use this in your code now - basically if you want to transform your data, and keep a copy of the old data, use map!

Using forEach

The cases where you would want to use forEach would fall under "side effect" scenarios. I pretty much only use forEach where I don't care about the result of the function that is being applied to the array elements. If you have some logging function (or in the simplest example console.log), the result of applying that function to the value is generally uninteresting, so forEach works well:

storeItems.forEach(item => console.log(`${item.name}: $${item.price}`));

Or, if you have some sort of action dispatching system where you dont care about the result of dispatching, you could take some array of actions and use forEach to dispatch them all.

const actions = [firstAction, secondAction]
actions.forEach(action => dispatch(action));

If you find yourself writing code like

storeItems.forEach(item => item.name = item.name.toUpperCase());

I would highly suggest you swap to using map instead. While the above is code that will compile and work, it is transforming the original dataset, and that can cause bugs that are difficult to track down!

Conclusion

Both map and forEach have their place when working with arrays of data. If you are wanting to make transformation to the data, reach for map. If you are looking to do effectful computations based on the data without modifying it, reach for forEach!

I hope this helped in identifying the right tool for the job at hand!