I often read JavaScript articles and noticed that many of them focus heavily on map
, filter
and reduce
, more so than other array methods. In my current React project, I noticed that I've used map
more but also that I unconsciously used forEach
a bunch of times, so I decided to dig into it more.
First, let's go over what we know about the two functions.
.forEach
- Goes over the array it is called on and executes the callback function on each element
- Changes the original array
- Returns undefined
// MDN's example
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
// expected output: "a"
// expected output: "b"
// expected output: "c"
.map
- Goes over the array it is called on and executes the callback function on each element
- Does not change the original array
- Returns a new array with the result
// MDN's example
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
As we saw, both functions do the exact same thing, and both are supported in all browsers. However, the way they work under the hood differs.
Differences
1. Use cases
map
returns a new array without mutating the original, so it makes sense to use it if we are planning to use the returned array elsewhere. However, if we don't mind mutating the original array and aren't planning to use it somewhere else, using forEach
is recommended. Per MDN:
You shouldn't be using
map
if you're not using the array it returns and/or you're not returning a value from the callback.
2. Approach
Because of map
’s nature, people who prefer a more functional approach will lean towards it. Functional programming is an approach to building software by using pure functions that take an input and return an output. In functional programming, functions do not modify variables outside of their scope, state is not shared and data is never mutated. This approach greatly diminishes the number of bugs that may be introduced into your application.
3. Performance
According to this post, map
seems to be much more performant than forEach
. However, I've since learned there's a big deal of controversy around this particular benchmark. It's not fair to compare the following two pieces of code
arr.forEach((num, index) => {
return arr[index] = num * 2;
});
let doubled = arr.map(num => {
return num * 2;
});
since the return
statement in the first example serves no purpose. Moreover, the performance of these functions depends on the implementation of JavaScript engines in different browsers, so the comparison is not so cut-and-dried.
4. Asynchronous programming
As stated by MDN, forEach
expects its callback to be synchronous, so it won't play well with any fancy async code you may have. map
however will be more tolerant.
Refactoring
In my project, I was using forEach
to iterate over my rounds array, which looks like this:
"rounds": [
{
"artists": [
{
"name": "Three Days Grace",
},
{
"name": "IDK",
},
...
]
},
...
]
I have an array of strings that contains images of the current round's artists, and I wanted to iterate over each artist and add the image property to the object. This is how I first achieved that:
const artistImages = getArtistData(artistData); // returns an array of strings
rounds.forEach((round, index) => {
round.artists[currentRound].image = artistImages[index];
});
return rounds;
I was calling this function in a component then assigning the returned array in state. Now, the state looked like this:
"rounds": [
{
...
"artists": [
{
"name": "Three Days Grace",
"image": "https://i.scdn.co/image/2a9ec8d494f8d0a52fd67c3239efc2b9e79a4ced"
},
{
"name": "IDK",
"image": "https://i.scdn.co/image/6594334f1d1a2e65394d27eb457ccff203886411",
},
]
},
...
]
Refactoring to use map
was quite simple and achieved the same result. It is exactly the same line of code, but now I'm returning something inside map
and saving it in a variable, then returning that variable to my component.
const artistImages = getArtistData(artistData); // returns an array of strings
const roundsWithImages = rounds.map((round, index) => {
round.artists[currentRound].image = artistImages[index];
return round;
});
return roundsWithImages;
And now hopefully my code is a little more readable and the likelihood of me messing up due to mutated variables is a little smaller!
Thank you for reading. Let me know how I can make this article better. Until next time 👋
Cover photo by Oliver Hale on Unsplash.
Top comments (2)
Really enjoyed!
Thanks Gbenga 😄