Map is one of the most useful array methods. It creates a new array with the exact same number of items as the source and can be used to modify values, change their type, add fields to objects, simplify objects etc. In this lesson we focus on practical use-cases for map & see it in conjunction with other array methods.
Array map creates a new array that is the same length as the original. It will call the function that you provide here once for each item in the source array, and it will use the return value to build up the new array. If we log this to the console, you can see we get 2, 4, 6, 8, and 10.
This function was called five times, and for each call item became equal to first one, then two, three, four, and then five. We return the result of multiplying that by two, and that's why we get this array. This doesn't affect the original array. If we log that above it, we can see that the first array is still intact.
Now, it's important to understand that it doesn't matter what you return from this function, the new array is always going to have five items in it.
Even if we remove this function body altogether, which would make this function return undefined, and log that's the console you can see that we get an array of five undefined values. This is the key to understanding when map is the appropriate array method to use.
Here are some examples. Let's say you have an array of string values like these, but inside your application, you need them to be numbers, so that you can perform calculations with them. This is a perfect used case for map, because we want a new array of the exact same length but with different values.
What we want out of the other end of this is simply the numbers one, two, three, four, and five. To implement that, we can return a call to the number constructor and pass along the item. This will convert the string to a number where possible, and if we log that to the console, you can see we now have one through five.
To make it clearer we can log the original array, and we can see that they are strings and these are numbers. Now that you understand this one to one mapping, you can start to come up with some really nice, concise code. Let's take for example an array that has two names in it, Shane and Sally. This first one has a couple of whitespace characters and there's one here also.
We want to create a new array that has those two strings but trimmed. We'll say the mapped array is equal to items.map. Now we're going to use an inline array function and we'll call it x.trim. If we logged that to the console, you can see we get exactly what we expect.
This function will be called twice, X will be equal to this string first. We call .trim on this string, which will remove this wide space and return it. The same thing happens to Sally. This is removed, and now map contains the items we expect. This is nice, but we are scratching the surface.
Let's take this array of two names, and let's say we want to convert those two names into two person-objects so that later on in our code, maybe in the UI or something like that, we can say person.first-name.
Again, this is a perfect use case for map, because we have an array of two items, and we want to create a new array that's going to use those two items as a base. If we say mapped is equal to items.map, and actually, for this example, we'll change this to names. Then inside the call-back, we'll have access to each name, and here we'll have the opportunity to return an object, instead.
We'll create the first-name property and set it equal to name, and then log that to the console. Now you can see the new array contains two objects, with the name set as the first-name property. To make this clearer, we can access each item maybe as you would later on in your application, here we have a person. If we log person.first-name, you can see that we have the desired result.
Another common use case for map is to add fields onto objects so that they better suit your application. For example, let's say you receive this array from an API. It's two objects with first name and last name properties, but in your App when you display people, you always use the full name and you may end up with some code like this.
I'm logging into the console for demo purposes, but this could be inside a component or something like that. Here we're adding the first name, a space, and the last name. If we use this quite a lot in our code, it will be much better to have a full name property on these objects, that way we can do full-name.
Let's add that property using map. We'll create a new array called mapped, and we'll call items.map, and we're going to return a new object that has a first name property equal to the first name property of the incoming object. The same for last name, and then the full name property which we will create by adding together the first name with a space and the last name.
Now, when we access this new array later on in our code, we have access to the full name property, as you can see here. Sometimes you'll want to take an array of objects and pull off a particular value from each object.
Take this example. Here we have a function that creates a HTML list. It takes an array as a parameter, and then it wraps each item in an LI tag, joins that together as a string, and then adds it in the middle of these two UL tags. We can see an action by calling it with an array and we'll say cat and dog.
Log in to the console, and you can see we get a UL and the two list items. The whole point here being that you can pass in any number of items and they'll be wrapped appropriately.
OK, how could we use this same function to print out a list of first names? Your initial thought may be that you could pass in the items array here, and then come into this function and modify it. Instead of simply using X, you can do x.first-name. That does actually work as you can see here, but we have now completely changed the implementation of this create HTML list.
We've explicitly tied it to objects that have a first name property, so we can't use this elsewhere in our app. We may as well change this to be, "Create personal list," but we don't want to do that. How can we get around this? This is where we come back to this idea of pulling values from objects.
Let's create another mapped array, and we're going to call items.map, and we use the shorthand array functions again. This time, we'll access the first name and that will be enough, because now if we log mapped to the console, you can see that we have Shane and Sally. It doesn't know anything about these objects anymore, it's two string values.
Then, we can pass that into our function as we did with the cat and the dog, and of course we need to remove this first name and we're back to where we were before. Of course, the difference is now, this does take any array of values. It can take our mapped array, or it can take an array of cat and dog, and you can see it still works.
Whenever you have an array of objects, and instead of that you want a simple array of a value from each object, this is all you need. Finally, as with all array methods, the real power comes when you begin to combine them together.
Let's modify this example slightly to make it a bit more readable. We're going to put new lines in between these LIs. I'm going to stick a new line here, and after the list there as well, and we'll even pad this in a bit. Let's log into the console again, and we can see we have a nicely formatted list.
To show map in conjunction with other array methods, let's pretend we have a chat application and we want to list the users who are currently active. We'll add an active property to each person, and then we'll add a third person who we will set to inactive. At the moment if we logged this, we're going to get all users, but we want to filter out any that have the active property set to false.
This is extremely simple. We call filter, here. And because we're calling filter before we do the mapping, we still have access to each full object. Because the filter method expects either a truthy or falsy value, we can return x.active. Log that to the console and you can see we get what we wanted.
This is the real power, because look how declarative this is. We take the items array and we filter it based on whether or not the active property is set to true. That will omit this object. When we get to this line, we're only going to have these two items in it.
Then calling map here is going to create an array that has Shane and Sally in it. That means when we finally call this function, we don't have to worry about this person because they are excluded further up the chain.