Array methods
JavaScript has plenty of built-in methods, with several being used to manipulate arrays. For instance,
the .includes()
method checks whether a specified element exists within an array:
const myArray = ['cat', 'dog', 'mouse'];
console.log(myArray.includes('dog')); // true
console.log(myArray.includes('cow')); // false
...this is only one of the many convenient array methods JavaScript offers; a full list of them can be found on MDN Web Docs.
Remembering every single method is impossible, but there are three methods you should
definitely know: .map()
, .filter()
, and
.reduce()
. These three methods are also referred to as higher-order functions.
A higher-order function is a function that operates on another function, either by taking it as an argument or returning it.
This article will cover all three of these higher-order functions and explain how they work; let's begin
with the .map()
function.
Using .map()
Here, I have an array called people
, which is full of objects; each object holds a property of name
and age
:
const people = [
{
name: "John",
age: 22,
},
{
name: "Jane",
age: 12,
},
{
name: "Jack",
age: 45,
},
{
name: "Jill",
age: 73,
},
];
...next, I want to loop over this array in order to retrieve all the name
values from each object, then store each value inside an empty array. Traditionally, this can be
accomplished by initializing an empty array and using a for
loop to
grab each name
value. Then, each value is pushed into the empty array by
using the .push()
method...
const onlyNames = [];
for (let i = 0; i < people.length; i++) {
onlyNames.push(people[i].name);
}
console.log(onlyNames);
// ['John', 'Jane', 'Jack', 'Jill']
...this works perfectly fine, but it's quite a bit of code. To fix this, I'll use the
.map()
function instead...
const onlyNames = people.map((individual) => {
return individual.name;
});
console.log(onlyNames);
// ['John', 'Jane', 'Jack', 'Jill']
...the .map()
function creates a new array by transforming every element in an array
individually. It takes in another function, also known as a "callback function"; the callback function takes
a parameter that represents the current element being processed in the array, which in this case
is individual
. Finally, the name
of each
individual
is returned and stored inside an array called
onlyNames
.
Despite both code snippets doing the exact same thing, the logic greatly differs. In the
.map()
function, the only logic being explicitly passed is
return individual.name
. Unlike the former example, you don't have to initialize an empty array,
create a loop, or push elements into the array — the .map()
function
handles everything. This makes the code much more concise, improves reusability, and reduces the
chances of bugs.
Using .filter()
The next higher-order function I'll cover is .filter()
. This function creates a new array by removing elements
that don't match the specified criteria. As an example, I'll use the same people
object from the previous explanation:
const people = [
{
name: "John",
age: 22,
},
{
name: "Jane",
age: 12,
},
{
name: "Jack",
age: 45,
},
{
name: "Jill",
age: 73,
},
];
...next, I want to create an array that only holds the names of those with an age
greater than 25. Traditionally, this can be accomplished like this...
const onlyOldPeople = [];
for (let i = 0; i < people.length; i++) {
if (people[i].age > 25) {
onlyOldPeople.push(people[i].name);
}
}
console.log(onlyOldPeople);
/*
[
{
name: "Jack",
age: 45,
},
{
name: "Jill",
age: 73,
},
];
*/
...the if
conditional statement will search for anyone older than 25
and add them to the empty array. Now, I'll accomplish the same thing with the .filter()
function...
const onlyOldPeople = people.filter((individual) => {
return individual.age > 25;
});
console.log(onlyOldPeople);
/*
[
{
name: "Jack",
age: 45,
},
{
name: "Jill",
age: 73,
},
];
*/
...just like with the .map()
function, the .filter()
function is much more concise with less logic — have a look at both code snippets side-by-side...
// Traditional way
const onlyOldPeople = [];
for (let i = 0; i < people.length; i++) {
if (people[i].age > 25) {
onlyOldPeople.push(people[i].name);
}
}
// .filter() way
const onlyOldPeople = people.filter((individual) => {
return individual.age > 25;
});
...furthermore, since the the .filter()
function only contains a single line of code,
it can be condensed even further...
// Traditional way
const onlyOldPeople = [];
for (let i = 0; i < people.length; i++) {
if (people[i].age > 25) {
onlyOldPeople.push(people[i].name);
}
}
// .filter() way
const onlyOldPeople = people.filter(individual => individual.age > 25);
...now you're looking at 141 characters compared to 71 characters — a 50% reduction in code size! It may not seem like much, but when you're working on bigger projects, the difference becomes significant, especially with flexibility.
Using .reduce()
The next higher-order function you should be familiar with is .reduce()
.
This function takes all the elements inside an array and "reduces" them into a single value. For this example,
I'll create an array of objects, with each object holding an amount
property
with different numbers:
const money = [
{
amount: 223,
},
{
amount: 342,
},
{
amount: 649,
},
{
amount: 195,
},
{
amount: 477,
},
];
...with the data given, I want to create a function that returns the sum of each
amount
. Traditionally, that would be accomplished like this...
let sum = 0;
for(let i = 0; i < money.length; i++) {
sum += money[i].amount;
}
console.log(sum);
// 1886
...sum
is initialized with a value of 0
but increases after each iteration. Simple enough, right? Now, I'll do the exact same thing using the
.reduce()
function.
Unlike the .map()
and .filter()
functions, the .reduce()
function works a little differently.
While it does take in a callback function like other higher-order functions, the syntax is a bit different —
have a look...
array.reduce((previousValue, currentValue) => {
// ...
}, initialValue)
...just like .map()
and .filter()
,
the callback function takes in the current value, except this time, it's the second argument. The first
argument will hold the previous value, and it's given an initial value
after the callback function. This may sound a bit confusing, but the logic is quite simple...
const finalOutput = money.reduce((sum, m) => {
return sum += m.amount;
}, 0)
console.log(finalOutput);
// 1886
- The
sum
is initialized with a value of0
. sum
is added with the first element,m[0].amount
, which holds a value of223
.sum
is now223
.sum
is added with the second element,m[1].amount
, which holds a value of342
.sum
is now565
.- This continues for every iteration until the final element is
added to the
sum
, which will print a final value of1886
.
Applying higher-order functions
The best way to get comfortable with new concepts is to apply them. Instead of using for
loops in
your code, opt for a higher-order function instead — they're shorter, have higher reusability, and they're easier to work with!