Higher Order Functions & Functional Composition

Published on 2021-10-24

Have you ever wondered what a Higher Order Function (HOF) is, and how it might help you when writing code? Well look no further!

In this post I will show some examples of where HOFs are used in daily JavaScript, how you can write your own, and as a bonus a small section on composing functions.

What are Higher Order Functions (HOF)?

Simply put, a higher order function is a function that does either, or both of the following:

  1. Take one or more functions as arguments.
  2. Returns a function.

Here is a simple example of some code that you may write that makes use of a HOF:

const nums = [1,2,3,4,5,6];

const isEven = number => {
  return number % 2 === 0;
};

// evens will be an array with elements [2,4,6]
const evens = nums.filter(isEven);

Here we make use of the array filter method which takes as an argument a function that takes a single argument (an element of the array) and returns true if the element should be kept, and false if the element should be discarded.

You might also find the above code written with an anonymous function instead, which would look something like this:

const nums = [1,2,3,4,5,6];
const evens = nums.filter(n => n % 2 === 0);

While the above code demonstrates filter, you will find many examples of passing in functions as arguments to other methods for arrays such as map, reduce, every, etc. This pattern will start to pop up all over the place in JavaScript code - you probably were already making use of this concept without knowing its name!

Extending our isEven function

One thing that is nice about HOFs is that they allow use to write some code to combine functions in new and interesting ways. Imagine our code from above is growing and we need to also be able to get a list of odd numbers. We could easily write an isOdd function that would be very similar to isEven, but we also know that in this case it would just be the exact opposite of isEven. Unfortunately we can't just write const evens = nums.filter(!isEven), even though that is basically what we want. What we can do is create a new function called not that takes a function as an argument, and returns a new function that will invert the value of the passed in function:

const nums = [1,2,3,4,5,6];

const isEven = n => {
  return n % 2 === 0;
};

const not = f => {
  return x => !f(x);
};

const isOdd = not(isEven);

// odds will be an array with elements [1,3,5]
const odds = nums.filter(isOdd);

Awesome! Our function not satisfies both requirements for being a HOF because it takes a function as an argument and it returns a new function as its result, which we bind to isOdd. You can make use of HOFs to build more complex functionality by reusing logic of smaller functions, sweet!

Cleaner Code With Function Composition

While function composition isn't strictly related to the topic of HOF, it is something you may want to use for writing clean functional code. I would suggest you reach for a library such as lodash/fp or ramdajs to grab their compose function. Here is the documentation for ramdajs's compose.

While writing not as a HOF, I did add some extra machinery by taking a function and returning a function to work in my example. The simplest, standalone version of not would be written as const not = v => !v;. That is, it just takes a boolean value and returns the inverse. I can write the not function this way if I make use of compose. Here is an example of doing just that:

import R from 'ramda';

const nums = [1,2,3,4,5,6];

const isEven = n => n % 2 === 0;
const not = v => !v;
const isOdd = R.compose(not, isEven);

const odds = nums.filter(isOdd);

In my opinion, this is the cleanest version of the code so far, and the best part is R.compose takes as many functions as necessary! This allows us to start writing functional code that is composable and easy to test and reason about!

Conclusion

In the end, Higher Order Functions are prevalent in JavaScript - if you stumbled across this while trying to learn there is a chance you were already making use of this concept without knowing it! If you end up leaning towards writing more functional JavaScript, HOFs will be a concept you make use of heavily, and when paired with composition the code will become easy to test, combine, and reason about!