In the last lesson, we started using the map function to loop through our data and map pieces of data
to our reusable components.
Now in this lesson, I want to go through map in greater detail and also look at some of the related functions
that help us deal with arrays such as map, filter, reduce find, and findIndex.
So go ahead and get the starting CodeSandbox, and then go ahead and fork your own copy.
All right, so here I've got an array of numbers up at the top, and what map allows us to do is to loop
through the array and create a new array by doing something with each item.
So, as you saw, the way that we call this is we need to get hold of an array in order to call map on it,
and inside this map function, it's going to expect a function.
So we're passing a function into another function.
Now the function that we pass in will determine what we actually want to do with each item.
So let's say that I wanted to maybe double each of these items. So I could create a function that takes
an input x and simply just returns the value of x multiplied by 2.
So this is a doubling function and it's pretty simple.
If I pass this function double into my map function, then it's going to loop through my numbers array
and for each of the numbers in there, it's going to put it as the input of this function and output a
new array with each item replaced with double the size of the previous one.
Let's go ahead and try it out. This method has an output and that output can be either captured, so let's
call it newNumbers and we can go ahead and console.log() it. So you can see in our console that we're
getting the values 6, 112, 4, 96 and 10, each of which are double the size of each of the items in our
numbers array. Now if you think about this, this is not exactly something that we couldn't do before right?
Because we already knew about the forEach and we've been using it to loop through arrays for a long
time now in the course.
So if we wanted to do this with forEach, we could have done it like this.
We could have created a new variable called newNumbers and set it to an empty array, and then we could
have gotten hold of our numbers array, and then called forEach.
And then inside this forEach function, it also expects a function,
right?
So let's go ahead and create another double function which takes a number x, and it gets hold of this
newNumbers array and pushes a new value which is going to be x multiplied by 2 into that newNumbers
array. And then we can pass that function, double(), into this forEach loop.
So this is how we would do it using the forEach,
rather than using map. So you can see that map is a lot more concise.
Now you might be thinking, "Well actually, when we've been using forEach, we don't actually define a separate
function right?"
So we could in fact make this a lot simpler by putting that function inside the forEach and making
it anonymous by removing its name.
So it would look something like this, a little bit simpler,
right?
But equally, we could have done the same with our map function.
We can also make that a lot simpler if we wanted to, by simply putting this function inside the parentheses
and then removing its name, and turning it anonymous. Whichever way you do it,
you'll notice that it's more concise using map because this function itself actually returns an output
which is a new array.
So unlike forEach where we have to create a new empty array, and then every time we do something with
each item inside the array we push to the new array. Instead, with map
it just does it all by itself.
This is really, really handy in React when we're creating custom components and mapping data to it. Now
another related and also quite a useful function is filter().
Let's say that we've still got our numbers array up here,
so let's just move it a bit closer,
and I wanted to filter on it,
well, as the name suggests, what it does is it's going to create a new array by keeping only the items
that return true.
What does that mean?
Well, let me show you a demo.
Let's say that we have our numbers array and I call the filter method and inside here again it expects
a function.
Let me write it out. Instead of creating a separate function,
I'm just going to create an anonymous function inside here.
So this filter function is going to look through each of the numbers inside this numbers array and for
each of these numbers, it's going to return only the ones that meet a particular criteria.
So we could say something like return num > 10.
In this case, we're looking through this numbers array here, and we're checking each of the numbers,
so we first start with 3 then 56,
and for each of these numbers, we're checking to see if they're greater than 10,
and if they are, then we're going to add it to a new array which is going to be the output of this function.
So let's create a const called newNumbers and set it to equal this.
And then we can go ahead and console.log() it. And you can see we get 56 and 48,
the only two numbers that are greater than 10. Now you can of course switch this up so make it create
an array where the numbers must be less than 10, in which case we get 3, 2, 5.
And this is basically a way of adding a filter to your array and providing a condition that you want
to check for,
and if that condition is met, and then create a new array with those items that actually return, true.
I find it quite helpful usually, thinking about these methods map, filter, and reduce in the context of a method
that you should already be pretty familiar with which is the forEach.
So let's think about how we might do this with a forEach loop. So we might create a newNumbers array
which is going to be empty,
then let's get hold of our numbers and then call forEach on it, and then inside here will add an anonymous
function which will loop through each of the numbers inside here.
So we have access to each of the numbers inside our numbers array and then we're going to check, we're
going to say if num is,
so we were checking less than 10 up here, less than 10,
well, then in that case we're going to push this number which meets this criteria into our array of new
numbers.
So newNumbers.push and we're going to push num in there.
Now when we log new numbers, you can see it's still the same but it obviously took a lot more effort
than simply just using the filter function.
Now the final one that sort of fits inside this set map, filter, and reduce, is the reduce function.
So the reduce function works by accumulating a value and doing something to each of the item in an
array.
So sounds a little bit confusing as well but it will be less confusing when we actually see it in action.
Let's say that I wanted to add and sum up all of the items in my numbers array.
Well, if I wanted to do that with forEach then I would have to say something like numbers.forEach,
and then let's create an anonymous function in here, forEach number in numbers,
we're going to create a new variable, which we will call newNumber and set it to 0.
And then inside this loop, we would have to get hold of a newNumber and add the value of the current
number in the array.
So it might help if I actually rename this, currentNumber. What this loop does is it goes through all
of the numbers in this array, and for each of the current number that it's looping through,
so the first time it'd 3, then it's going to add that number to our new number.
So 0 becomes 3 and then the next time it loops around
this is 3 and it becomes 59 et cetera, et cetera, until we end up with the final value, so we can go ahead
and log newNumber which is equal to 114.
This is the roundabout way of doing it.
Now what if we wanted to do it using our reduce function?
Well, it's actually a lot simpler.
So we could say, numbers.reduce and then we can pass in a function which takes an accumulator, as
well as the current number,
and this is going to be the equivalent of that previous variable.
And then this is going to be the number which is equal to each and every iteration through the array.
And then inside the reduce function,
I'm going to return the accumulator plus the currentNumber. And if we go ahead and save this to a variable
called newNumber, because we're really console logging it down here, then you can see the result is the
same as the previous method using forEach.
Now it might help if you actually go ahead and just console.log()
the value of accumulator and currentNumber every time the loop is run in order to understand how this
reduce function works. You can see that the first time the loop is run the accumulator is already set
as the first value, and the currentNumber gets set as the second value.
The next time it's run, the accumulator has already been added to the currentNumber,
so it's now equal to 56, but the currentNumber now moves onto the next item in the array, and so on and
so forth until we get to the end of the array and we end up with our total value.
So those three functions are probably some of the most useful JavaScript functions that actually exist
even before ES6. If you take a look at the MDN Developer Docs for map, filter, and reduce which
I'll link to in the Course Resources, you can take a look at how they work and what parameters they
take, but also notice how their compatibility is, across all browsers.
This was introduced way before ES6 and you can safely use this code anywhere on any browser. But the
next two that I want to talk about, the find and findIndex, were actually introduced relatively recently.
So what are they useful for?
Well, find is a function that's going to help you find the first item that matches in an array.
So for example inside our numbers array, we could go ahead and call numbers.find, and again it expects
a function.
So let's loop through all the numbers in our numbers array and then go ahead and find the first value
that is greater than 10.
So, return num > 10. What this does, unlike the filter, is it's not going to loop through the
entire array,
it's going to stop as soon as one of these returns true. If we go ahead and save this to a const
and log it,
you can see that it loops through our array but it's stopped as soon as it found the first item that
was greater than 10. And findIndex works in a similar way,
but instead of finding the first item, instead what it does is it finds the index of the first item that
matches.
S o in this case, if we change find to findIndex, you can see it works pretty much the same way,
but now we're getting the index of that first number that matches the criteria which is, of course, the
index 1, because arrays start from 0.
So all of these functions are not for you to memorize,
it will be really hard to remember all of these. But instead, I recommend really understanding what's
going on, and what the goals are of each of these methods
map, filter, reduce,
find, and find index so that when you actually have a need for something that one of these functions
might be able to help you achieve, somewhere in the back of your mind you might have a light bulb go
off and think, "Oh yeah, there was a function somewhere whether it was map, filter, or reduce, I can't remember,
but one of these can probably do what it is that I need. And then go and have a look at the docs and
find the function that you actually need, and then quickly look through the demo and the documentation
to see what it actually does and how to use it.
So as I always stress, memorization is not what we do in the post at Google world.
So in order to test your understanding, I've got a challenge for you.
Go ahead and comment out any code that you've already got,
and feel free to save it inside this CodeSandbox for future reference if you want. But you'll notice that
I've also included the emojipedia file that came from our previous code challenge, and what I want
you to do is to go ahead and import the emojipedia const from our ./emojipedia file. And
then you'll remember that the emojipedia const is also an array, right?
So when we log it you can see we've got an array of three objects and each of these have a property
called meaning which contains a whole bunch of text.
So your goal is to create a new array that just has the meaning text,
for example this one, this one, and this one,
but here's the catch, you have to truncate the text so that it only has a maximum of 100 characters. Here's
what it would look like if you have completed the challenge successfully.
So here's my new array that I've created using some sort of function,
and it logs each of these emoji meanings but it caps them, if you notice, at a hundred characters.
So they are all equally long.
And this is kind of useful
a lot of times when we're creating websites where we want these sizes of cards, or boxes to be even across
our entire page. And we might just do a truncation like what I've got here. As a hint, you will need to
use a another method which you might have come across ages ago in the JavaScript section which is called
substring. I've linked to the documentation on this method
so have a look at it.
Have a think about this problem and see if you can achieve this outcome and complete the challenge. Pause
the video now and give it a go.
All right.
Our starting point is three objects in an array. So we know that the map function helps us create a new
array by doing something with each of the items.
And that kind of matches what we want, right?
Because in our case, we want to create a new array of meanings,
and the doing something is to truncate it to 100 characters, and we're going to do that to each item
in this emojipedia array.
Now that we've settled on the map function, let's go ahead and call it.
So we'll say emojipedia.map().
Now inside this map function, it of course expects a function which is going to give us every single
emoji entry.
So let's just call it emojiEntry.
So we've got three emoji entries, each are an object,
and the first time this loops through it, what do we want to do with the emojiEntry?
What do we want to do with it?
Well, we want to take the emojiEntry, so let's just focus on the first object for now, the emojiEntry's
meaning,
so we're going to be tapping into emojiEntry.meaning, and we're going to try and use substring to
cut it down to 100 characters. Based on this demo,
you can see that these substring takes the string and cuts it between the index specified at the first
and the second positions.
So in this case 0, 1.
So it starts from 0 and ends at 3. 2, 3.
So we end up with 'oz' printed out. In our case if we want 100 characters printed, we can simply
use these substring method and cut it from 0 to 100.
Now that we've got this newly formatted meaning, what are we going to do with it?
Well, we're just going to return it.
And what this does is it's going to build a new array which we can save into a const, newEmojipedia,
and it's going to create it from the meanings in our emoji entries from our emojipedia with only
the first hundred characters.
So let's go ahead and log this newEmojipedia. And you can see that I've now got this new array and I've
cut the meanings, all at a hundred characters.
So they are now equally long.
And this is achieved by using our map function which maps through this emojipedia array,
and for each of the entries, I've gotten hold of the meaning text, and then I've cut it down to the first
hundred characters, and then I've returned it to be added to this new array. If you didn't manage to complete
this challenge I recommend heading back to your code and trying to do this yourself from scratch, and
play around with the code until it makes sense.
It's also worth having a quick read of each of these pieces of documentation which as usual is really
high quality, and really helps you get even more understanding of each of these functions.
Now in the next lesson, we're going to learn about something that is ES6 specific and it's going
to help us to cut down on the length of our functions even more.
And that is the fat arrow also known as the JavaScript arrow function. For all of that and more,
I'll see you there.