Let’s Talk about JavaScript’s Higher-Order Functions — Pt. 1

Taking a look at

Tiffany Kanjanabout
5 min readMar 8, 2021
.map, .filter, and .reduce explained with emojis

As a Bootcamp graduate, I still find some programming vocabulary pretty intimidating and constantly fear using the wrong term or phrase when describing code. This is the hardest part: understanding the core concepts.

“Higher-order functions” is one of the phrases I first struggled with at first. In 3 Ways to Write Cleaner Code, I wrote about the DRY principle, or Don’t Repeat Yourself. In functional programming, one of the ways to accomplish this is by using higher-order functions, which take a function as an argument, return a function, or both. It is simply a decorative phrase for a simple concept.

As a quick review, remember that JavaScript functions are objects that can be

  • passed as arguments (which are called callback functions)
  • stored as variables
  • returned from other functions
  • used in arrays
  • assigned as object properties (which are just methods, a function inside an object)

These characteristics are true for any other type of data as well! So what’s the big deal about them? Think back on a function you’ve written that is more than 6 lines. Higher-order functions allow us to abstract logic from our functions and create helper functions that focus on smaller tasks.

They also help our code become more declarative: short, simpler, and readable.

In this post, we’ll be looking at the commonly used higher-order functions–Array.prototype methods: .filter() and .map() as well as their alternative for loop solution.

.filter()

Definition + Syntax — MDN

/* 
Definition
:
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
*/
// Syntax:
let newArray = arr.filter(callback(currentValue[, index[, array]]) {
// return element for newArray, if true
}[, thisArg]);

When to Use:

Sometimes we only need certain values in array. We can apply .filter() to return a new array that contains that subset. This method is a great choice because it doesn’t mutate the original array.

In Action:

From the Codewars problem, Vowel Count

Return the number (count) of vowels in the given string.

We will consider a, e, i, o, u as vowels for this Kata (but not y).

The input string will only consist of lower case letters and/or spaces.

Input: "abracadabra"
Expected Output:
5
const vowels = ['a', 'e', 'i', 'o', 'u']const getVowelCount = (word) => {
let vowelsCount = 0;
let splitWord = Array.from(word)

splitWord.filter(letter => {
vowels.includes(letter)
? vowelsCount++
: null
});

return vowelsCount;
}

First, we declared the variable vowels that holds an array of all valid vowels. Next, we define our function getVowelCount the ES2015 (ES6) way. Inside getVowelCount, we declare our counter variable vowelCount and splitWord, which splits the given string input into an array of its characters.

Now, we’ll use .filter to compare each of the letters in our splitWord array to see if it matches any of the valid vowels in our vowels array. In this function, we are saying: in splitWord, let’s look at each letter and see if it matches (or is included) in the vowels array. If it is included, let’s increment our counter, if it isn’t a vowel, do nothing. Then we return the vowelCount once that is finished!

Let’s compare it to the for loop solution:

const getVowelCount = (word) => {
let vowelCount = 0;
let vowels = ['a', 'e', 'i', 'o', 'u'];
for (let i = 0; i < word.length; i++) {
for (let j = 0; j < vowels.length; j++) {
if (word[i] === vowels[j]) {
vowelCount++;
}
}
}
return vowelCount;
}

With filter, the solution becomes a bit more readable and helps us avoid writing nested for loops.

.map()

Definition + Syntax — MDN

/* 
Definition
:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
*/
// Syntax:
let newArray = arr.map(callback(currentValue[, index[, array]]) {
// return element for newArray, after executing something
}[, thisArg]);

When to Use:

While .forEach() could be used to achieve the same thing, it’s better to use .map() instead to implement a high-order function that doesn’t mutate the original array. Use .map() when you need to do something to each element inside of an array and need a new array with those values. We’ll pass .map() a function to execute on each element in order to receive those values.

In Action:

Let’s say you need an array of every letter of the alphabet and lowercase. Instead of hardcoding all 26 letters, you could write a function using the staticString.fromCharCode() method which returns a string created from a sequence of specified UTF-16 code units. In this example, we’ll be using the Decimal value of the corresponding ASCII character in the alphabet. You can find a table of those values here.

const alphabet = [...new Array(26).keys()]
.map(i => String.fromCharCode(i + 97))

First, we create a new array holding the numerical values of their corresponding index using the spread operator, the Array constructor, and the keys method. Let’s break down each return value:

[...new Array(26)] => 
[
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined, undefined,
undefined, undefined
]
[...new Array(26).keys()] =>
[
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25
]
.map(i => String.fromCharCode(i + 97)) =>
[
'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x',
'y', 'z'
]

Knowing that the decimal value of the lowercase letter a starts at 97, we can now map over this new array, passingString.fromCharCode each number in our array plus 97 to get every letter in the alphabet.

Let’s compare a for loop solution:

function setAlphaIndex() {
let alphaIndex = [];
for (let i = 0; i < 26; i++) {
alphaIndex.push(i)
}
return alphaIndex;
}
function getLowecaseAlphabet() {
let alphabet = [];
let alphaIncrements = setAlphaIndex();
for (let i = 0; i < alphaIncrements.length; i++) {
let letter = String.fromCharCode(i + 97)
alphabet.push(letter)
}
return alphabet
}

Instead of creating one giant function, I separated the logic for creating a new array with corresponding indices as its values. Now, I’m calling my helper function inside getLowerCaseAlphabet() and setting it to a variable. It’s definitely not the cleanest of code, but I wanted to illustrate what is happening under the hood of the .map solution!

Codewars is a great place to practice switching between writing with both for loops and JavaScript’s built-in methods. In the next post, we’ll take a look at .reduce() and .includes() and how they can be utilized in a HackerRank problem!

--

--

Tiffany Kanjanabout

Full stack web developer. Frontend and design enthusiast. Avid rock climber and amateur photographer.