Nested Higher Order Functions in JavaScript

Higher-order functions are functions that either take functions as parameters or return functions as values (or both). They allow for a great deal of power and flexibility in programming. However, it can be difficult for beginners to understand how they are supposed to work, particularly when a nesting of higher-order functions is involved. For example, consider the following:

var mathy = function(x) { return function (y) { return function (z) { return (x / y) - z; } } }

How do you pass the appropriate parameters to this function? Say you want to find the answer to

(4 / 3) - 2

A simple

mathy(4, 3, 2)

is not going to work. All those parameters would be passed to the outermost function, but not the inner function that it returns (nor the inner function returned by that one).

Understanding how to work with nested functions like this will go a long way toward helping us read and write more advanced JavaScript code. Let’s build up this understanding, starting from simple cases.

I. The Basics

Passing parameters with first-order functions is straightforward, so let’s start there. Consider the following:

var simpleGreeter = function(name) { return 'Hi, ' + name + '!'; };

To pass a parameter to simpleGreeter , we simply enclose it in parentheses:

simpleGreeter('Bob') //'Hi, Bob!'

But what happens if we evaluate simpleGreeter without the parentheses?

simpleGreeter //[Function]

To better understand what’s going on, it’s useful to think in terms of a substitution heuristic. This heuristic tells us that whenever we see the name of a function, we can substitute its body enclosed in parentheses. So:

simpleGreeter //[Function]

becomes

(function(name) { return 'Hi, ' + name + '!'; }) //[Function]

and

simpleGreeter('Jane') //'Hi, Jane!'

becomes

(function(name) { return 'Hi, ' + name + '!'; })('Jane') //'Hi, Jane!'

This heuristic is going to help us understand nested higher-order functions, but keep in mind that it is not generally applicable in JavaScript. Objects, for example, are passed by reference, not value, and we cannot straightforwardly apply substitution in that kind of case.

II. Higher-Order Functions

Our simpleGreeter function is rather one-dimensional at the moment. But we can make a more flexible relative by turning it into a higher-order function.

var highGreeter = function(greeting) { return function(name) { return greeting + ', ' + name + '!'; } };

We can then create different kinds of greeters as follows:

var greeterGoodDay = highGreeter('Good day'); var greeterHey = highGreeter('Hey'); greeterGoodDay('Lisa') //'Good day, Lisa!' greeterHey('Lisa') //'Hey, Lisa!' greeterHey('Takahiro') //'Hey, Takahiro!'

This is obviously a powerful kind of thing to be able to do, but how does it work? Let’s use our substitution heuristic to break it down. Start with the following example:

greeterHey('Bill') //'Hey, Bill!'

We can substitute the body of greeterHey for its name as follows:

(highGreeter('Hey'))('Bill') //'Hey, Bill!'

So what does highGreeter do? It takes a greeting parameter and returns the following function:

function(name) { return greeting + ', ' + name + '!'; }

When it returns that function, it replaces greeting with the parameter that was passed in ((This is an example of a closure, but since closures are an interesting topic in their own right, I’ll leave that for another time.)), so in our example, it actually returns

function(name) { return 'Hey' + ', ' + name + '!'; }

So we can make the following substitution:

(highGreeter('Hey'))('Bill') // | // | // \_/ (function(name) { return 'Hey' + ', ' + name + '!'; })('Bill')

It should be more obvious what’s going on here. This function just is greeterHey , and ‘Bill’ is being passed as the name parameter ((You might recognize this form as an IIFE, or immediately-invoked function expression. Wrap an anonymous function in parentheses and follow it by another pair of parentheses to call that anonymous function immediately.)).

We created intermediate functions like greeterHey and greeterGoodDay in order to move step by step from the higher-order highGreeter function to outputs like ‘Good day, Lisa!’. This is a useful thing to do, but it’s not necessary. Consider the following:

highGreeter('Yo')('Mario') //'Yo, Mario!'

Using substitution, we get:

(function(greeting) { return function(name) { return greeting + ', ' + name + '!'; } })('Yo')('Mario') //'Yo, Mario!'

In this case, our first set of parentheses enclose a higher-order anonymous function. What are the other sets of parentheses doing? Start with the parentheses enclosing 'Yo' . It should be obvious that these are passing a parameter to our higher-order function. But it’s important to notice that they are also calling that function. Recall the difference between the following two cases:

simpleGreeter //[Function] simpleGreeter('Queen Mary') //'Hi, Queen Mary!'

The first case returns the function without calling it whereas the second calls it. In order to make this point clearer, let’s take a moment to consider some functions that take zero parameters.

III. Taking a Step Back

Consider the following:

var five = function() { return 5; }; newFive = five; valueFive = five(); newFive //[Function] newFive() //5 valueFive //5 valueFive() //TypeError: Property 'valueFive' of object #<Object> is not a function

By setting valueFive equal to five() , we set it equal to five ’s return value, which is the number 5. Thus, valueFive is not itself a function. newFive , on the other hand, was set equal to five (without the use of parentheses). Thus, it became a function itself. These assignments could be rewritten as follows, according to our substitution heuristic:

var five = function() { return 5; }; var newFive = five; // | // | // \_/ var newFive = (function() { return 5; }); var valueFive = five(); // | // | // \_/ var valueFive = 5;

Let’s push this idea further by creating a higher-order version of five :

var highFive = function() { return function() { return 5; } }; highFive //[Function] highFive() //[Function] highFive()() //5 var five = highFive(); var valueFive = highFive()(); five //[Function] five() //5 valueFive //5 valueFive() //TypeError: Property 'valueFive' of object #<Object> is not a function

highFive is a function that takes no parameters and returns a function that takes no parameters. That returned function returns a value of 5. Thus, calling highFive with one set of parentheses will just return another function. But adding another set of parentheses calls that returned function, which returns 5. This is why valueFive in this example is a value and not a function. Make sure that these points are clear in your mind before moving on.

One important thing to see is that for each nested returned function, we need another set of parentheses to get down to calling the innermost return. Here is an extreme example:

var reallyHighFive = function() { return function() { return function() { return function() { return 5; } } } }; reallyHighFive() //[Function] reallyHighFive()() //[Function] reallyHighFive()()() //[Function] reallyHighFive()()()() //5

IV. Putting it All Together

Now, reallyHighFive is about as useful as a real-life high five, so let’s return to our greeter functions to see how these examples can help illustrate passing parameters to more useful higher-order functions. Recall that greeter looked like this:

var highGreeter = function(greeting) { return function(name) { return greeting + ', ' + name + '!'; } };

We could use it in the following way:

var greeterGoodDay = highGreeter('Good day'); greeterGoodDay('Mildred') //'Good day, Mildred!'

This works precisely because the following works:

highGreeter('Good day')('Mildred') //'Good day, Mildred!'

Notice what’s happening here. The first set of parentheses calls the highGreeter function and passes in 'Good day' as greeting . The second set of parentheses calls the anonymous function returned by highGreeter and passes in 'Mildred' as name . We can make this as complex as we’d like:

var superGreeter = function(greeting) { return function(place) { return function(nickname) { return function(name) { return greeting + ', ' + name + '! Welcome to ' + place + ', ' + nickname + '.'; } } } }; superGreeter('Hey')('Berlin')('old pal')('Hans') //'Hey, Hans! Welcome to Berlin, old pal.'

With this more complex greeting function, we can create all kinds of new functions ((This is an example of currying, but it’s a case where currying is pretty clearly the wrong strategy. I’m only using it to illustrate how nested higher-order functions work.)):

hiParisBuddyGreeter = superGreeter('Hi')('Paris')('buddy'); helloTokyoGreeter = superGreeter('Hello')('Tokyo'); hiParisBuddyGreeter('Franz') //'Hi, Franz! Welcome to Paris, buddy.' helloTokyoGreeter('friend') //[Function] helloTokyoGreeter('friend')('Yuki') //'Hello, Yuki! Welcome to Tokyo, friend.'

If you’re writing a program and you need to greet users based on dynamic settings, I wouldn’t recommend using a function like this. But hopefully it helps you understand how nested higher-order functions work.

The best way to get these concepts to sink in is to interactively build and evaluate functions from the command line. I’d recommend Node.js.