Introduction
The map() method in JavaScript is a powerful tool for creating a new array by transforming each element of an existing array, without modifying the original array. It iterates over each element of an array, similar to a for loop however, unlike a for loop, this method does not change the original array. Instead, it returns a new array containing the results of applying a function to each element.
In this article, we will explore the map() method in depth, covering what it is, why it is useful, and how to use it effectively.
What is map() in JavaScript?
As mentioned in the introduction, this is an array method that allows you to transform elements in an array. It works similarly to other looping constructs like forEach or for loops, but with a key difference: it does not mutate the original array.
To clarify what we mean by mutation, consider this: mutation refers to changing the original array. With map(), the original array remains unchanged, and instead, a new array is returned. Here's an example to illustrate this:
let arr = [1, 2, 3, 4, 5];
const multiplyArr = arr.map(element => element * 2);
console.log(multiplyArr)
// output: [ 2, 4, 6, 8, 10 ];
console.log(arr);
// output: [ 1, 2, 3, 4, 5 ]
Have you noticed that we doubled the values in the arr array by multiplying each element by 2 using the map() method? We stored the result in the multiplyArr variable and then printed it with console.log. It returns a new array with the doubled values.
Next, we checked the output of the original array (arr), which remained unchanged. This demonstrates that the original array was not mutated.
How to use map() in JavaScript?
Using map() is simple, as shown above. However, let’s review its core structure for clarity.
Here’s the syntax of the method:
array.map(function(currentValue, index, arr), thisValue)
Did you notice that the function accepts two parameters? The first one is a callback function, while the second one is the this value used during the execution of the callback function. The callback function is mandatory, but the this value is optional; we can use it if needed or leave it out. That’s what we do most of the time.
Callback function (required)
This function is executed once for each element in the array. It can itself accept up to three parameters:
- currentValue (required): The current element being processed.
- index (optional): The index of the current element.
- array (optional): The original array on which .map() was called; passed as the third argument to the callback for context or reference during iteration. The array map was called upon.
Check this example, and you will understand how all these parameters work:
Examples:
const numbers = [10, 20, 30];
const result = numbers.map(function(currentValue, index, array) {
console.log(`Element: ${currentValue}, Index: ${index}, Full Array: ${array}`);
return currentValue * 2;
});
/* output:
Element: 10, Index: 0, Full Array: 10,20,30
Element: 20, Index: 1, Full Array: 10,20,30
Element: 30, Index: 2, Full Array: 10,20,30 */
So here, if we look at the first row, where Element: 10 indicates that the element is 10, and Index: 0 shows that the index of the first element is 0, while Full Array represents the arr parameter, which is the entire array: [10, 20, 30].
thisArg (optional)
thisArg (optional): A value to use as this inside the callback function when .map(). executes, allowing you to control the context within the callback.
const numbers = [10, 20, 30];
const multiplier = {
factor: 10
};
const result = numbers.map(function(number) {
return number * this.factor;
}, multiplier); // thisArg works here
console.log(result); // [100, 200, 300]
Have you seen how thisArg is used in the example? It might seem a bit strange to you because thisArg is rarely used with the method, so you may not have seen it before.
Let me explain the code I used above to make it clearer for you. There’s nothing particularly special about it, except for the use of multiplier as an additional parameter. This is the second, optional parameter in the method.
I started the map() as usual, and within the method, I returned number * this.factor. Here, number represents each element of the array, * is the multiplication operator, and this.factor refers to the value we want to multiply each element by. As you can see below, we have an object with a property factor: 10 that provides this value.
multiplier.const multiplier = {
factor: 10
};
This is the value we passed as thisArg but you might be a little confused by the this keyword. In JavaScript, this refers to the context in which a function is executed. In simple terms, it points to the object that is currently being used when the function runs.
So, in our example, the this keyword refers to the multiplier object, which we passed as the second argument to the map() method. Inside the callback function, we used number * this.factor, where:
- number is each element of the array.
- *: is the multiplication operator.
- and this.factor accesses the factor property from the multiplier object.
I hope this clears up any confusion about the syntax and use of the method especially how thisArg works. Now, let’s move on to why map() is so useful and when you should use it in your JavaScript code.
Why is map() useful in JavaScript?
map() is not just useful—it’s extremely useful. In many programs, we often need to work with the same array in different parts of the code, for various purposes and operations. Using this and other non-mutating methods helps ensure that the original array remains unchanged. This allows us to reuse the same array multiple times without worrying about accidental modifications.
You might not realize how important this is at first, so let me explain further.
Suppose you have an array like [10, 20, 30], and you want to perform different operations with it such as multiplying each element or summing all the elements. The question is: which method should you use?
The simple answer is map(). It doesn’t modify the original array but returns a new one. This lets you manipulate data without altering the original array. As long as you use non-mutating methods, you can freely manipulate data in different ways without side effects.
Let’s look at this in practice.
Example with a for Loop
const numbers = [10, 20, 30];
for(let i = 0; i < numbers.length; i++) {
numbers[i] = numbers[i] * 5;
}
console.log(numbers); // original array: [50, 100, 150];
Have you seen that when we tried to multiply the elements using a for loop, it mutated our entire original array with the updated values? Let’s look at the same example using the map() method below.
Example with map()
const numbers = [10, 20, 30];
const multiply = numbers.map(number => number * 5);
const subtract = numbers.map(number => number - 5);
console.log(multiply)
// Array with multiplying: [50, 100, 150]
console.log(subtract)
// Array with subtraction: [5, 15, 25]
console.log(numbers);
// original Array: [20, 40, 60]
Now, see this example where we perform two operations using map() without affecting the original array. I hope you understand the value of this, as it is very useful in programming and helps us avoid writing extra code.