In this lesson, you'll take a look at the .map() array method that allows you to transform each element in an array. The .map() method effectively "maps" the values to a new array.
For instance to map numbers to their double, conceptually you can represent it like this:
1 -> 2
2 -> 4
3 -> 6
4 -> 8
Where each number gets "mapped" to the double of itself in a new array.
Like the .filter() method, the .map() method lends itself to functional style programming since it doesn't mutate the original array, but instead returns a brand new array.
## When to Use the Map Method
A map in programming terms is a transformation of values. The .map() method is a way for you to say, "transform each value according to my instructions". Maybe you want to double each value in the list? With .map(), it's straightforward:
const values = [1, 2, 3, 4, 5];
values.map((value) => value * 2); // [2, 4, 6, 8, 10]
The .map() method takes a callback function as an argument just like .filter() or .forEach(). This callback function is called for each element in the array, and the return value of the callback is used to create a new array.
Remember to return explicitly if you have more than one line in the arrow function. Or else you'll just get an array full of undefined!
const values = [1, 2, 3, 4, 5];
values.map((value) => {
value * 2;
}); // [ undefined, undefined, undefined, undefined, undefined ]
values.map((value) => {
return value * 2;
}); // [2, 4, 6, 8, 10]
Arguments to the .map() Callback
Like many array methods, the callback accepts more arguments than just the element in the array. With .map() it calls the callback with the element, index, and original array.
const values = [1, 2, 3, 4, 5];
values.map((value, index, array) => {
console.log(value, index, array);
});
// 1 0 [ 1, 2, 3, 4, 5 ]
// 2 1 [ 1, 2, 3, 4, 5 ]
// 3 2 [ 1, 2, 3, 4, 5 ]
// 4 3 [ 1, 2, 3, 4, 5 ]
// 5 4 [ 1, 2, 3, 4, 5 ]
So if your mapping logic relies on things like adjacent elements, or aspects of the whole array, then you can make use of these extra arguments.
An Example of Using .map() to Transform Data
Let's say you have a list of objects that represent some user data. You want to take this list of user data, which contains a name property and a title property, and create a list of HTML elements that contain the user's name and title. This is a great usage for .map():
const userList = document.querySelector('#user-list');
const users = [
{ name: 'Jeff', title: 'Developer Advocate' },
{ name: 'Janet', title: 'CEO' },
{ name: 'Joe', title: 'CTO' }
];
users
.map((user) => {
const listElement = document.createElement('li');
listElement.textContent = `${user.name} - ${user.title}`;
return listElement;
})
.forEach((element) => userList.appendChild(element));
In this example, you have a userList element that for the purpose of this example starts out as empty. You also have an array of users that you want to display in the userList element as a series of li items.
You used the .map() method to transform each user object into an li element, with the user's name and title as the text content.
Then, with the new array returned from .map() you chain on a .forEach() to add each of those transformed elements, which are now li elements, to the userList element. Pretty neat and tidy!
Best Practices: It's worth noting that the example shown here can be improved. The issue is that by appending each li element to the DOM one by one, the browser has to reflow and repaint the page for each element.
You can use a DocumentFragment to avoid reflow and repaint costs associated with repetitive direct DOM manipulation:
const userList = document.querySelector('#user-list');
const fragment = document.createDocumentFragment();
const users = [
{ name: 'Jeff', title: 'YouTuber' },
{ name: 'Mary', title: 'CEO' },
{ name: 'Joe', title: 'CTO' }
];
users
.map((user) => {
const listElement = document.createElement('li');
listElement.textContent = `${user.name} - ${user.title}`;
return listElement;
})
.forEach((element) => fragment.appendChild(element));
userList.appendChild(fragment);
Using a DocumentFragment allows all the li elements to be added to the DOM in one operation, with one repaint and reflow. This can lead to better performance when dealing with a large number of elements.
Summary: JS Array Map Method
In this lesson you've:
- Seen that
.map()takes a callback function to apply a transformation to each element, creating a new array with the transformed values. - Seen that
.map()does not mutate the original array. - Recognized the importance of explicitly returning values from the callback when using multi-line arrow functions to avoid ending up with
undefinedin the resulting array. - Discovered that the callback provided to
.map()gets more information than just the current element; it also gets the index of the element and a reference to the entire array. - Applied your knowledge to map user objects to list elements (
li), enabling you to generate dynamic HTML content based on array data, exemplifying the practical utility of.map().