Map() vs. forEach()

Map vs forEach in JavaScript – What Is the Difference?

One of my most loved functions in JavaScript might be map() and forEach. They both started to exist since ECMAScript 5, ores5 in short.

On that post, I am going to talk about the main difference between each and show you some examples of their usages.

Basically, looping over an object in JavaScript counts on whether or not the object is an iterable. Arrays are iterable by default.

map() and forEach() are included in the Array.prototype, so we don’t need to think about iterable. If you want to study further, I recommend you check out what an iterable object is in JavaScript!

What Are map() and forEach()?

map and forEach are helper methods in array to loop over an array easily. We used to loop over an array, like below, without any helper functions.

let array = ['1', '2', '3'];
for (let i = 0; i < array.length; i += 1) {
  console.log(Number(array[i]));
}
// >>>>>>>>>>>>>return values:
// 1
// 2
// 3

The for loop has been with us since the very beginning of the JavaScript era. It takes 3 expressions: the initial value, condition, and final expression.

This is a classic way of looping an array. Since ECMAScript 5, new functions have appeared to make our file more easier.

1.map()

map does exactly the same thing as what the for loop does, except that map creates a new array with the result of calling a provided function on every element in the calling array.

It takes two parameters: a callback function that will be invoked later when map or forEach is called, and the context variable called this argument that a callback function will use when it’s invoked.

const arr = ['1', '2', '3'];
// callback function takes 3 parameters
// the current value of an array as the first parameter
// the position of the current value in an array as the second parameter
// the original source array as the third parameter
const example = (str, i, res) => {
  console.log(`${i}: ${Number(str)} / ${res}`);
};
arr.map(example);
// >>>>>>>>>>>>>return values:
// 0: 1 / 1,2,3
// 1: 2 / 1,2,3
// 2: 3 / 1,2,3

The callback function can be used as below.

arr.map((example) => { console.log(Number(example)); })

The result of map is not equal to the original array.

const arr = [1];
const new_arr = arr.map(d => d);
arr === new_arr; // false

You can also pass the object to the map as this argument.

const obj = { name: 'Christos' };

[1].map(function() {
  // { name: 'Christos' }
  console.dir(this);
}, obj);

[1].map(() => {
  console.dir(this);
}, obj);

The object obj became the thisArg for map. But the arrow callback function can’t get obj as its thisArg.

This is because arrow functions work differently from normal functions. Visit this article to see what’s different between arrow functions and normal functions.

2.forEach()

forEach is another looping function for an array but there’s a difference between map and forEach in use. There are two parameters that map and forEach can take — a callback function and this  argument which they use as their this.

const arr = ['1', '2', '3'];
// callback function takes 3 parameters
// the current value of an array as the first parameter
// the position of the current value in an array as the second parameter
// the original source array as the third parameter
const example = (str, i, origin) => {
  console.log(`${i}: ${Number(str)} / ${origin}`);
};
arr.forEach(example);
// >>>>>>>>>>>>>return values:
// 0: 1 / 1,2,3
// 1: 2 / 1,2,3
// 2: 3 / 1,2,3

What’s different?

[1,2,3].map(d => d + 1); // [2, 3, 4];
[1,2,3].forEach(d => d + 1); // undefined;

forEach doesn’t ensure the immutability of an array if you change values inside an array. This method only ensures immutability when you don’t touch any values inside.

[{a: 1, b: 2}, {a: 10, b: 20}].forEach((obj) => obj.a += 1);
// [{a: 2, b: 2}, {a: 11, b: 21}]
// The array output has been changed!

So When to Use map() and forEach()?

Since the main difference between them is whether or not there is a return value, you would want to use map to make a new array and use forEach just to map over the array.

Here an example:

const people = [
  { name: 'Christos', whatCanDo: 'canDo1' },
  { name: 'George', whatCanDo: 'canDo2' },
  { name: 'John', whatCanDo: 'canDo3' }
];

 makeWorkers(people) => {
  return people.map((person) => {
    const { name, whatCanDo } = person;
    return <li key={name}>My name is {name}, I can do {whatCanDo}</li>
  });
}

<ul>makeWorkers(people)</ul>

On the other hand, forEach is useful when you want to do something with the data without creating a new array. By the way, the example could be refactored using filter.

subjects.filter(subject => mySubjectId.includes(subject.id)).length;

To summarise, I recommend you use map when creating a new array that you will use, and use forEach when you don’t need to make a new array, but rather, there’s something you want to do with the data.

Speed Comparison

Some posts mentioned map is faster than forEach. So, I was curious if it’s for real. I found this comparison result:

Map vs forEach in JavaScript - What Is the Difference? 1

source : https://jsperf.com/foreach-v-map

The code looks very similar but the results are the opposite. Some tests said forEach is faster and some said map is faster.

Maybe you are telling yourself that map/forEach is faster than the other, and you might be right. I’m not sure, honestly. I think readability is much more important than the speed between map and forEach when it comes to modern web development.

But one thing’s for sure — both of them are slower than the built-in feature of JavaScript, for loop.

Conclusion

map and forEach are handy functions for looping over an iterable object and might beautify your code and give you more readability.

But one really important keynote to keep in mind is to understand what each does and when to use each.

map would be good when you want to make a new array that does not affect the original array, and forEach would be nicer when you just want to map over an array.

Resources:

Leave a Reply

Your email address will not be published. Required fields are marked *

Rating*