JavaScript Array .map() vs .forEach()
Brett Martin
Posted on October 17, 2021
originally published @ CatStach.io
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, useforEach
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!
Posted on October 17, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 25, 2024
October 6, 2024