Map & forEach

Open the project folder

In our starter files, open the index.html page from this lessons folder:

02.Arrays-In-More-Depth > 07.Map-forEach

The forEach method

I want to now show you two more array methods called forEach and map. These two methods are also iteration methods, so they loop over each array value, and then run a callback function for each one.

Lots of the array methods we have covered so far are more specific, such as sorting an array, filtering, checking if one value exists, but forEach and map are more general use.

Their purpose or use is only limited to the code we write in the function. First let’s look at forEach.

In the starter files, we have 2 arrays:

let numbers = [72, 33, 108, 222, 6];
let posts = [
  { title: 'How to learn Javascript', body: 'bla bla bla' },
  { title: 'How to be a ninja', body: 'bla bla bla' },
  { title: 'How to be a ninja part 2', body: 'bla bla bla' },
];

And we will begin by calling forEach on the numbers array, using the shorter arrow function syntax:

numbers.forEach((number) => );

Just as a recap, if we can keep it all on one line, we can leave out the return keyword. If we want to use multiple lines, we add the curly braces and the return keyword like this:

numbers.forEach((number) => {
  //code
  return
});

For this, we can do anything we want such as multiplying the numbers:

numbers.forEach((number) => console.log(number * 2));

The index number is also available if we add it in as a parameter:

numbers.forEach((number, index) =>
  console.log(`number ${index}: ${number * 2}`)
);

All these indexes begin at zero, we can also change this to display from 1 onwards if we prefer, by adding +1 to the output:

numbers.forEach((number, index) =>
  console.log(`number ${index + 1}: ${number * 2}`)
);

Any code can be wrote inside of this function, taking our posts array from above, let’s look at an example with an array of objects. This is going to take our posts title, and transform the text to uppercase:

posts.forEach((post) => console.log(post.title.toUpperCase() ) );

Just as we have been using lots of array methods in this section, toUpperCase is also a method, but it is a string method, so we call it on a string of text such as our post title.

The map method

This is forEach and we also have something similar called map:

posts.map((post) => console.log(post.title.toUpperCase()));

The console shows the same result as when using forEach, so what is the difference?

Differences between map and forEach

There are a couple of reasons they differ, and one is the return value. To see this, first remove the console log wrapper, leaving this:

posts.map((post) => post.title.toUpperCase());

We then need to store the return value into a variable, and change back to use forEach:

const newPosts = posts.forEach((post) => post.title.toUpperCase());
console.log(newPosts); // undefined

We get back undefined because nothing is returned. The forEach method will run a function for each array value and modify the original array.

Map on the other hand, leaves the original array, and returns a new one with the modified values, which you can see by changing this to use map:

const newPosts = posts.map((post) => post.title.toUpperCase());
console.log(newPosts); // ['HOW TO LEARN JAVASCRIPT', 'HOW TO BE A NINJA', 'HOW TO BE A NINJA PART 2']

This return value is one of the differences. Another difference is we can also chain multiple methods using map.

Chaining methods

At the end of the map method, we add a dot followed by the method we want to chain, such as filter():

const newPosts = posts
  .map((post) => post.title.toUpperCase())
  .filter((value) => value === 'HOW TO BE A NINJA PART 2');

console.log(newPosts);

This will return a new array with the found post. If we wanted to check if this title is included in the array, we could use the some() method:

const newPosts = posts
  .map((post) => post.title.toUpperCase())
  .some((value) => value === 'HOW TO BE A NINJA PART 2');

console.log(newPosts); // true

This will return true rather than a new array. We can use all methods we have previously looked at, including findIndex to find the index number of this value:

const newPosts = posts
  .map((post) => post.title.toUpperCase())
  .findIndex((value) => value === 'HOW TO BE A NINJA PART 2');

console.log(newPosts); // 2

You can see with these examples that although all these methods may look complex to begin, many of them are structured the same, but just return different values. None of this chaining is available if we change to use forEach:

const newPosts = posts
  .forEach((post) => post.title.toUpperCase())
  .findIndex((value) => value === 'HOW TO BE A NINJA PART 2');

console.log(newPosts);

This chaining is not possible because forEach returns undefined, rather than a new value:

Uncaught TypeError: Cannot read properties of undefined (reading 'findIndex')

To recap, if we want to modify the existing array and do not need a new one returned, we use forEach. We use map if we want to leave the original array untouched and return a new array with the values, and it is also good for chaining too.