loading...

JS Basics: Higher Order Functions

farmanp profile image Farman Pirzada ・3 min read

What is a higher order function?

Higher order functions are functions that operate on other functions. This allows us to create functional abstractions and not just value abstractions.

In JavaScript, there are three commonly used higher order functions you should know about: map, reduce, and filter. Let's look at each one with a real world example:

I want the names of employee's who's letter start with A

In order to do that, I will use the higher order function map:

map

const employees = [
  {name: "Doug", gender: "M", occupation: "Help Desk"},
  {name: "Alex", gender: "F", occupation: "CTO"},
  {name: "Ada", gender: "F", occupation: "Developer"},
  {name: "Sandra", gender: "F", occupation: "Developer"},
  {name: "Beatrice", gender: "F", occupation: "Designer"},
  ]

let employeeNamesWithA = []; 

employees.map((employee) => {
  // Ternary opearator to check if an employee's name starts with A
  return employee.name.includes("A") ? employeeNamesWithA.push(employee.name) : employeeNamesWithA;
})

//[ 'Alex', 'Ada' ]

But you can't just have an example and expect to understand, right? How is map a higher order function exactly? It takes a map of employees with properties and returns an array. Map makes a copy of the data so it WILL NOT modify the original one.

employees.map((employee) => {

Next we require another function for map, which is includes():

includes()
  return employee.name.includes('A') ? employeeNamesWithA.push(employee.name) : employeeNamesWithA;

map is used to programmatically iterate through a list

filter

Let's say I want to create a filter function for my dropdown that gives me results by occupation, but this time I want the object as well:

const employees = [
  {name: "Doug", gender: "M", occupation: "Help Desk"},
  {name: "Alex", gender: "F", occupation: "CTO"},
  {name: "Ada", gender: "F", occupation: "Developer"},
  {name: "Sandra", gender: "F", occupation: "Developer"},
  {name: "Beatrice", gender: "F", occupation: "Designer"},
  ]

let employeesWhoAreDevelopers = employees.filter(employee => employee.occupation.includes("Developer")); 

This method also WILL NOT affect the original data.

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

reduce

Now, let's say your team needs to determine where to allocate their resources next. Because they don't want to be bothered by manually counting each other (much simpler, but so much potential for human error! /s), they would rather a program tell them instead (time is $$$, there are more important things to worry about, like this MVP that needed to be done YESTERDAY!). So, the goal is to group by occupation count. This will determine who the next person will need to be on the team:

const employees = [
  {name: "Doug", gender: "M", occupation: "Help Desk"},
  {name: "Alex", gender: "F", occupation: "CTO"},
  {name: "Ada", gender: "F", occupation: "Developer"},
  {name: "Sandra", gender: "F", occupation: "Developer"},
  {name: "Beatrice", gender: "F", occupation: "Designer"},
  ]

const groupByEmployeeOccupation = employees.reduce((total, employee) => {
  total[employee.occupation] = (total[employee.occupation] || 0) + 1; 
  return total; 
}, {})

//{ 'Help Desk': 1, CTO: 1, Developer: 2, Designer: 1 }

Great! Now we have a decision to make. We ignore CTO, because there can only be one! And we find that after talking with Doug, he seems to be alright on his own right now. Beatrice on the other hand is swamped! We probably should've taken her point in retro for "Need to Improve: I need another designer", but now we at least have a program to tell us it's true!

So just what the heck is going on here? It looks more complex than map and filter right? How does reduce even work?

Well it takes two arguments (it can take four total, but not in this example) that function as an accumulator and the currentValue. An accumulator is what to do with each iteration throughout the data. The accumulator will ultimately have a final resulting value of all the data. The currentValue is what the iteration is currently at. So:

total[employee.occupation] = (total[employee.occupation]

total is representing the accumulator and taking the currentValue, which is the employee's occupation key and setting it a value of how many times that occupation comes up + 1.

reduce executes a reducer function (that you provide) on each element of the array, resulting in single output value

Summary:

  • Higher order functions take a function as an argument
  • map, reduce, and filter are the most common examples of higher order functions in JS

Sources and Further Reading:

Posted on by:

farmanp profile

Farman Pirzada

@farmanp

keeping things practical

Discussion

pic
Editor guide