The Array.forEach Method in JavaScript

Published: Tuesday, May 24, 2022
Updated: Saturday, May 28, 2022

Greetings, friends! As you may know, JavaScript and other programming languages typically provide for loops for iterating over objects such as arrays.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

for (let i = 0; i < array.length; i++) {
  console.log(array[i]);
}

/* OUTPUT:
apple
orange
banana
*/

It's very common for developers to use the Array.forEach method to iterate through arrays instead.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach(fruit => {
  console.log(fruit);
})

/* OUTPUT:
apple
orange
banana
*/

The code looks much cleaner now! Most people will say it's considered better practice to use the Array.forEach method instead of a for loop. Although for loops are slightly more performant, the code is much easier to read and follows a more functional approach.

Let's look at the Array.forEach method's documentation more closely. According to MDN, this method can accept two parameters and returns undefined.

javascript
Copied! ⭐️
forEach(callbackFn, thisArg)

The first parameter - callbackFn

The first parameter we pass into the forEach method is a callback function, and the second parameter is thisArg, a value to use as the this context when executing callbackFn. It's really rare to use the second parameter. It's also an optional parameter. Let's just look at the first parameter, the callback function. We'll discuss the second parameter later.

The Array.forEach method expects a callback function that has one, two, or three parameters. The second and third parameters are optional.

javascript
Copied! ⭐️
forEach((element) => { /* ... */ })
forEach((element, index) => { /* ... */ })
forEach((element, index, array) => { /* ... */ })

Using a Callback Function with One Parameter

Let's use the Array.forEach method with a callback function that has one parameter.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach(fruit => {
  console.log(fruit);
})

/* OUTPUT:
apple
orange
banana
*/

The code snippet above passes in an arrow function as a callback function. We could have just as easily defined our own function and pass that into the forEach method instead.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

function logElement(element) {
  console.log(element);
}

array.forEach(logElement);

/* OUTPUT:
apple
orange
banana
*/

This is why using a forEach method makes the code look really clean. It's saying that for each element in the array, execute the logElement function.

Using a Callback Function with Two Parameters

Let's now take a look at using the forEach method with a callback function that has two parameters. The second parameter will be the index of the element of the array.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach((fruit, index) => {
  console.log(index + '. ' + fruit);
})

/* OUTPUT:
0. apple
1. orange
2. banana
*/

This seems like an odd list. Let's bump up the index by one.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach((fruit, index) => {
  console.log((index + 1) + '. ' + fruit);
})

/* OUTPUT:
1. apple
2. orange
3. banana
*/

Again, we can write a function and pass that into forEach as a callback:

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

function logElement(element, index) {
  console.log((index + 1) + '. ' + element);
}

array.forEach(logElement);

/* OUTPUT:
1. apple
2. orange
3. banana
*/

Using a Callback Function with Three Parameters

Next, let's try using a callback with three parameters. The third parameter will be the array we're calling the forEach method on.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach((fruit, index, thisArray) => {
  if (thisArray.length !== 1) {
    thisArray.shift();
  }
});

console.log(array); // OUTPUT: ['banana']

So this may look like a weird example, but let's step through it piece by piece. For each element in the array, we will execute the callback function we passed in. It starts with the first element, apple. At this point, the array still has three elements. Therefore, the thisArray.shift() line will be executed.

The variable, thisArray, is the same value as the variable, array. In fact, thisArray is a reference to array. This means that if we modify thisArray, we will modify array as well. The shift method removes the first element from an array. Therefore apple will be removed from thisArray. This means array is modified too.

The forEach method will keep calling our callback function containing the shift method and will keep removing elements until we're left with only one element in the array. We then log the value of array to the console and find that it only contains one value, banana.

Notice that we defined the array using const at the top of the code snippet yet the array was still modified. Even though const stands for "constant," we did indeed modify the array. This is because const only prevents reassignment (using the equal sign to set the variable to another value).

In practice, you should avoid modifying the array inside the forEach method. I only did it to show an example of what you could do with the third callback parameter. As stated on MDN, modifying an array during iteration could lead to unexpected results. You would think that the forEach method in our example would run three times, since we have three elements in our array, but it actually ran twice.

javascript
Copied! ⭐️
const array = ['apple', 'orange', 'banana'];

array.forEach((fruit, index, thisArray) => {
  console.log('Running...');
  if (thisArray.length !== 1) {
    thisArray.shift();
  }
});

If you run the code snippet above, you'll see that Running... is logged to the console two times, not three.

The second parameter - thisArg

We have now seen how to use the forEach method with a callback function with one, two, and three parameters. However, the callback function was only the first parameter we can pass into the forEach method. It also accepts a second parameter, thisArg, which is optional.

As mentioned previously, it's rare to use this second parameter. You'll typically see it when people are implementing a complex feature or trying to support old legacy code. Let's see an example of how we might use the thisArg parameter in the forEach method.

javascript
Copied! ⭐️
function Player() {
  this.spells = [];
  this.count = 0;
  this.hasHeal = false;
}

Player.prototype.add = function (array) {
  array.forEach(function updatePlayer(element) {
    this.spells.push(element);
    this.count++;
    if (element === 'heal') this.hasHeal = true;
  }, this);
};

const nate = new Player();
nate.add(['fireball', 'thunderbolt']);
console.log(nate.spells); // [ 'fireball', 'thunderbolt' ]
console.log(nate.count); // 2
console.log(nate.hasHeal); // false

const sam = new Player();
sam.add(['blizzard', 'bubble beam', 'heal']);
console.log(sam.spells); // [ 'blizzard', 'bubble beam', 'heal' ]
console.log(sam.count); // 3
console.log(sam.hasHeal); // true
warning
Arrow functions do not bind their own this context and will use their parent scope instead. Assigning an arrow function to Player.prototype.add will cause an error.

In the above code snippet, we are creating a Player object by calling a function. Before JavaScript introduced the concept of classes, it was common to make objects using functions and assigning properties to them using the this keyword.

Since JavaScript is a prototypal language, we can add methods to the player's prototype. Within the Player.prototype.add method, we are calling forEach and passing a value of this as the second parameter. In this context, the this keyword refers to the Player prototype. This allows us to add update properties on instances of our Player object. In our example, we have two instances: nate and sam.

When we run nate.add(['fireball', 'thunderbolt']), the player, "nate," will have each "spell" added to the list of spells. The spell count will be updated to match the total number of elements in the array. If one of the spells is called "heal," then the hasHeal property will be set to true.

The above code snippet may not seem like a clean approach, but it could be considered performant, since we only have to iterate through the array once to update multiple properties on a single Player object. However, there are much cleaner ways to write this code.

Conclusion

This has been a comprehensive guide to the forEach method in JavaScript. In summary, you use the forEach method to iterate through an array, similar to a for loop. The forEach method accepts two parameters: a callback and a value to use as the this context when executing the callback. The callback function can accept three parameters: the current element being processed, the index of that element in the array, and the array forEach was called upon. The forEach method is a great way to make your code cleaner and easy to understand!

Resources