- Define how the
map()
method works - Demonstrate
map()
withArray
s - Demonstrate
map()
with complex data structures
As developers, we find ourselves responsible for all sorts of common, but
tedious, tasks, such as iterating over arrays. Although a for
loop will work
for these tasks, we can take advantage of a method like map()
to save
ourselves work and to organize and optimize our code, resulting in more readable
and understandable functions.
Array.prototype.map()
is a method that iterates over an array and applies a
function to each element, modifying it in some way. The result is then returned
as a new array, leaving the original array the same (but remember, not any
elements we modify directly; that requires defensive copying). This is super
helpful, because it saves us from having to create a new array ourselves and
copy stuff in there. It also leaves the elements in the original array
unchanged, which helps protect our code from bugs.
As mentioned above, we use map()
when we want to perform an action on each
element in an Array
, and "gather" the results into a new Array
. We'll start
by looking at how we would build the functionality ourselves, using a for...of
loop, then show how map()
can save us work and improve our code.
We'll also use this as a chance to demonstrate some of the power of functions in JavaScript. We'll write the code four times, making it increasingly efficient and expressive each time.
In this example, we are using a standard bit of iteration code. The code below
recreates the functionality of the native .map()
method using for...of
. But
because for...of
(and for
as well) is a general function that can be used
to do lots of things, another programmer would have to examine the loop's inner
workings to determine exactly what the code is doing.
const students = ["harry", "ron", "hermione", "ginevra"];
const rollCall = [];
for (const student of students) {
rollCall.push( student + " the wizard" );
}
//=> rollCall = ["harry the wizard", "ron the wizard", "hermione the wizard", "ginevra the wizard"];
If we use the .map()
method, on the other hand, we are saying to other
programmers: "Expect a new array to come out of this after each element is
modified in some way!"
Let's look at a few different ways to implement the native .map()
method.
function studentRollCall(student) {
return student + " the wizard";
}
const students = ["harry", "ron", "hermione", "ginevra"];
const rollCall = students.map(studentRollCall);
//=> rollCall = ["harry the wizard", "ron the wizard", "hermione the wizard", "ginevra the wizard"];
We use map()
when we want to transform the elements in an array in some way.
To do this, we pass a function as an argument; that function (the callback) is
what executes our desired transformation. In JavaScript, arguments can be
primitive types like Number
or String
, but they can also be work. Very
few other programming languages allow that!
The iterator function map()
calls the callback for each element in turn,
passing the element as an argument, and stores the return value in a new
Array
. When the iterations are complete, it returns that new array.
This code is more expressive than the version using for...of
because as soon
as a developer sees that map()
is being used, they know a lot about what the
code is doing.
Note that this code is using a named function as the callback. This is
perfectly valid, but the studentRollCall
function isn't doing much work. We
may want to streamline our code a bit more by using a function expression
("anonymous function") instead.
const students = ["harry", "ron", "hermione", "ginevra"];
const rollCall = students.map(function(student) {
return student + " the wizard";
});
//=> rollCall = ["harry the wizard", "ron the wizard", "hermione the wizard", "ginevra the wizard"];
By defining a function expression inline, we're able to tighten up our code without changing its functionality or making it less expressive.
Thanks to arrow functions, we can shorten up the function even more:
// When the parameter list is only one element, we can drop () !
const students = ["harry", "ron", "hermione", "ginevra"];
const rollCall = students.map(student => student + " the wizard");
//=> rollCall = ["harry the wizard", "ron the wizard", "hermione the wizard", "ginevra the wizard"];
The code now fits on one line! We've pared down all that noisy JavaScript code
in the for...of
version by using map()
along with more efficient JavaScript
syntax. This makes our code even more expressive: that single line of code tells
us everything we need to know about what the code is doing.
Let's use the map()
function on a trickier data structure — a list of objects.
To start things off, we have an array of robots. We want to activate all of
them. To activate a robot, we need to mark it as such using the isActivated
boolean, and also double its number of modes:
const robots = [
{ name: 'Johnny 5', modes: 5, isActivated: false, },
{ name: 'C3PO', modes: 3, isActivated: false, },
{ name: 'Sonny', modes: 2.5, isActivated: false, },
{ name: 'Baymax', modes: 1.5, isActivated: false, },
];
const activatedRobots = robots.map( robot => {
return Object.assign({}, robot, {
modes: robot.modes * 2,
isActivated: true,
});
});
console.log(activatedRobots);
/*
Result:
[
{ name: 'Johnny 5', modes: 10, isActivated: true },
{ name: 'C3PO', modes: 6, isActivated: true },
{ name: 'Sonny', modes: 5, isActivated: true },
{ name: 'Baymax', modes: 3, isActivated: true }
]
*/
We could, of course, accomplish the same thing using a for
or for...of
loop,
but using the native map()
function frees us from having to create an empty
array, code the looping mechanism, push the modified values into the empty
array, and return the modified array at the end. Instead of having to rewrite
the iteration code every time we need to modify elements in an array, map()
allows us to focus all our effort on building the actions we need in our
callback function.
Let's put our newly acquired knowledge of map()
to use! We just uploaded 10
coding tutorials online, but some of them have inconsistent casing. We want all
the titles to be "title case", in other words, the first letter of each word
should be capitalized. Create a new array containing the names of the tutorials
with proper title case formatting. For example, 'what does the this keyword mean?'
should become 'What Does The This Keyword Mean?'
.
const tutorials = [
'what does the this keyword mean?',
'What is the Constructor OO pattern?',
'implementing Blockchain Web API',
'The Test Driven Development Workflow',
'What is NaN and how Can we Check for it',
'What is the difference between stopPropagation and preventDefault?',
'Immutable State and Pure Functions',
'what is the difference between == and ===?',
'what is the difference between event capturing and bubbling?',
'what is JSONP?'
];
Run learn
and ensure that tests are passing.
map()
takes 2 arguments — a callback and the optional context. The callback is
called for each value in the original array and the modified value is added to a
new array. Its return value is a new array that is the same length as the
original array. Using map()
saves time while making the code simpler and more
expressive.