JavaScript Higher Order Functions Explained

NOTE: You can now watch this tutorial on YouTube via: https://www.youtube.com/watch?v=0CqXpEaMs10. Enjoy!

JavaScript can be a quite difficult language at times to learn. While JavaScript starts out easy: It’s simple enough to open up a code editor and type out a few basic programs that do math, or even copy and paste some JQuery code into your HTML — if you start looking at how JavaScript is ACTUALLY written by professionals, you might feel cold shivers up your spine.

One aspect in particular is the use of functions inside functions. If you are a newbie programmer, I know what you are thinking already… this sounds complicated, maybe I should back away now.

It’s Not That Complicated, But It Can Feel Alien At Times

I’m assuming here that you know some basics. If you feel comfortable with the following, read on:

  • Creating a variable
  • Making an array
  • Using semicolons (or not using them!)
  • Using a for loop, or a while loop (or both!)
  • Using console.log
  • Writing a function and have it do something basic, like sum two numbers.
  • Copying and pasting JavaScript into a console or a script in a webpage.

If you know this much, you’re good!

So What Are Functions Inside Functions?

Let’s look at some basic code to create, and use a function:

function sumTwoNumbers(x,y){
    return x + y;
}

var x = 10;
var y = 20;
var result = sumTwoNumbers(x,y);
console.log(result);

What would be the result of this code block? Try it out for yourself!

If you’re good with the above, let’s move on. Now let’s add a function inside a function. Refresh your page or clear your console and paste in the following.

function sumTwoNumbers(x,y){
    return function(){
        return x + y;
    }
}
var x = 10;
var y = 20;
var result = sumTwoNumbers(x,y); 
console.log(result);

What do you see now after running this code block in result on the console? Hmm, that’s weird — no sum came back! It just says Function.

That’s right, read the code above again — slowly. The sumTwoNumbers function doesn’t return x+y, it returns another function. Inside that nested function is the our original return statement x+y.

So how do we get the sum of x+y? Well, we have to call the nested function too! Good thing for us it’s saved in result, so result essentially becomes a function too!

Surprised? You can save functions inside variables too in JavaScript! Let’s try that out as well by resuming with our exercise.

function sumTwoNumbers(x,y){
    return function(){
        return x + y;
    }
}
var x = 10;
var y = 20;

var result = sumTwoNumbers(x,y); 
result();

Ta-da! We called the function!

But nothing happened Vijay! I don’t see anything in the console.

Correct, you are getting the hang of this already young padawan!

To see our result return x+y we must save that result somewhere — so let’s save the result in another variable.

function sumTwoNumbers(x,y){
    return function(){
        return x + y;
    }
}
var x = 10;
var y = 20;

var result = sumTwoNumbers(x,y);
var newResult = result(); //The result variable is now a function and we called it!
console.log(newResult);

Yay, peace has been restored to Earth! You can now see the result again in the console. Alternatively, you can also just console.log(result()) and that would work too — you didn’t need to save the function in a new variable — if you know what you are doing.

Let’s Get More Complicated

Okay, I hope you are now ready to bend your mind a little bit. This is the part you probably were waiting for. What are higher order functions?

Think of higher order functions as basically the difference between telling a computer to do something step by step by step in gruesome detail and telling the computer to do some task consisting of multiple steps; but you don’t care what those steps are so long as you get the result in a quick and easy way.

Better said, it’s the difference between manual and automatic shift like in car.

Most people don’t care about the details of shifting, they just want to get from point A to point B, so long as their car does that (and does it extremely well), people will continue to purchase automatic transmissions. Yes, some people still love boasting that they can drive with manual transmission, but in this day and age no one really cares.

In programming, you can think of a higher order function as a step towards “declarative programming”, where you tell a program what to do and let it do the work necessary to get it done (the details are not important to you).

Contrast that to “imperative programming”, where you do care about the details — possibly to the point of OCD behavior.

There are use cases for both declarative and imperative programming styles, just like there are use cases for manual and automatic transmissions. If you want FULL control over every aspect of your code, use imperative programming. If you just need to get the job done, then use declarative programming.

Let’s Now Return To Code Samples

You learned about nested functions. Let’s now do some more practice with them, now working with the idea of declarative and imperative coding styles locked in our mind.

Let’s add numbers to a total using a for loop in JavaScript:

var total = 0;

for(var i=0; i<10; i++){
    total += i; 
}

console.log(total);

What is the value of total?

Got the result? Cool, now let’s review — was this code done in an imperative way or a declarative way? Manual or Automatic?

Looks kind of manual to me. We have to declare the loop, set a range using i, then add each value of i to total. What if we want to do subtraction, multiplication and division? Take a moment before reading on to think out your solution.

How Do We Turn This Code Into Something More Declarative?

The for loop is the most manual aspect of the code from before. Let’s put it in a function!

function forRange(maxRange, doSomething){
    for(var i=0; i<maxRange; i++){
        doSomething()
    }
}

Our for loop went from being a for loop by itself into now a for loop buried inside a function called forRange. By calling forRange we get a for loop every time, and we don’t have to care about the internal details of how the for loop works, so long as it does the job of looping through some number and doing something with that number.

That’s exactly what we have defined here with this function, it takes two parameters (just like x and y earlier in sum). The two parameters are maxRange and doSomething.

maxRange is the maximum amount of times you want the for loop inside to run. So a maxRange could be 100 times. doSomething could be another function– hey a nested function! Remember that? Let’s try it out.

function forRange(maxRange, doSomething){
    for(var i=0; i<maxRange; i++){
        doSomething()
    }
}

forRange(100, function(){
    console.log("Hello World");
});

You should see Hello World appear 100 times in your console. Now let’s look at this code and read it. Rather than create a separate function above in my code elsewhere, I just wrote a function inside as my second argument after 100.

We can do that in JavaScript — it’s completely legal. This is called an anonymous function (anonymous because it has no name). You can write anonymous functions as arguments to another function. You can also save anonymous functions to variables like so:

var sum = function(x,y){
    return x + y;
}
var result = sum(1,2);
console.log(result);

Here sum is a variable that saves an anonymous function, which we can then call as you see in the second line.

Note: You can’t write an anonymous function by itself — it has to be saved in a variable. This would be an error:

function(){
    console.log('hello');
}

^Without a name, how can we call this function? It’s unreachable.

So why does this code below work? We didn’t save it in a variable!

forRange(100, function(){
    console.log("Hello World");
});

We didn’t, but JavaScript did when setting up this function. Let’s review the function definition again.

function forRange(maxRange, doSomething){
    for(var i=0; i<maxRange; i++){
        doSomething()
    }
}

When you set parameters like maxRange and doSomething, the JavaScript compiler program creates variables called maxRange and doSomething that are scoped (or made locally available to this function forRange). You can’t access these variables outside the function, they don’t exist — but they do temporarily for the life of the forRange function — whenever you call it.

In other words, every time you call forRange, you get with it its own internal variables maxRange and doSomething which get set to whatever you pass in as arguments.

So your code actually looks more like this when being read by the JavaScript compiler:

forRange(100, function(){
    console.log('hello');
})
function forRange(){
    var maxRange = 100;
    var doSomething = function(){
        console.log('hello');
    };

    for(var i=0; i<maxRange; i++){
        doSomething();
    }
}

As a result of passing arguments 100 and the function(){ console.log('hello') } into the forRange function, we are asking the compiler to create those variables internally and set them to the values we supplied.

Pro Tip: I find often, it’s best to start with a function call (where you see the arguments or values being passed), then work backwards to reading the function declaration (where you define the function). In this way, the definition actually makes more sense because you see the example use first before you read a dry, boring definition. I’m visual, so I like examples first before I read dry textbook info.

With Me So Far?

I know this is getting hairy. But bear with me, you’re almost there!

You definitely have this in your backpocket. All you need to do now is just return to our conversations above about declarative vs imperative programming.

At this point, we’ve created a new function called forRange which can take any range now and doSomething.

Isn’t that a bit declarative? Hey function forRange, do whatever I tell you in my anonymous function maxRange amount of times! You don’t actually need to write a for loop any more, it’s part of this program – the boring details are gone! You can just use forRange now whenever you need a quick for loop!

Yay! I guess?

Let’s modify our forRange function slightly. We need to be able to access each individual value of i in our for loop. Otherwise, this code just does a useless action like console.log('hello') for say 100 times. It’d be better if we could get the value of the current for loop iteration and do something with it; at the very least have access to it. If we could get the current loop number, we could add it back to our total from our code above.

function forRange(maxRange, doSomething){
    for(var i=0; i<maxRange; i++){
        doSomething(i);
    }
}

Here we are allowing doSomething to have access to the internal for loop’s i value as an argument. Technically we are not calling doSomething yet even though this looks like a function call, because we haven’t called forRange. Until we call forRange, our nested function doSomething will remain frozen along with the for loop. However once forRange fires off, the for loop runs and automatically so does doSomething with each instance of i passed to it.

So let’s call forRange now and unfreeze doSomething.

var total = 0;

forRange(10, function(i){
    total += i;
})

console.log(total)

Our anonymous function maps over to doSomethingdoSomething is now able to fire off because forRange is firing off. It’s like we turned on the car and now everything else is starting to fire off — without turning on the car, nothing else can turn on. But now that forRange is on, so is doSomething and our for loop.

The variable total lives outside the nested functions, and so is reachable even from inside another function and a nested function. Think of it like this, your brain sees everything you see with your eyes, because your eyes live outside the brain; but you can never see what your brain truly sees because your brain doesn’t live outside you. I know, deep…

Basically code outside of a function can be read inside from a nested function. This code is called a global variable. Code that lives inside a function is local only to the function and dies after the function finishes.

function myInternalVariable(){
    var total = 10;
}
console.log(total); //We don't have a global total variable, so error!
var total = 10;
function sum(){
    console.log(total);
}
sum(); //total is global, so it can be viewed even when inside another function
var total = 10;
function sum(){
    function add(){
        console.log(total)
    }
    add();
}

This still works too! Nested functions can still see top level or global variables.

Putting It All Together

You now have a lot of JavaScript advanced knowledge in your head. What are you going to do with this much power?

Code declaratively of course!

Let’s check out some other higher order functions to help us actually boil all this stuff down, once and for all. You can do this, you’re ready.

We saw that we could make a simple forRange function that could take any range, maxRange and do some action, doSomething, which had global access to its i value in the for loop — but doSomething and the for loop were frozen in time — until forRange ran. You can’t put the pedal to the gas without turning on the engine in a car. Makes sense right?

So let’s explore more “frozen” functions.

function forEach(array, callback){
    for(var i=0; i<array.length; i++){
        callback(array[i]);
    }
}

var myArray = [1,2,3,4,5,6,7,8,9,10];
var result = 0;
forEach(myArray, function(item){
    result += item
});
console.log(result);

Our function callback is frozen until we call forEach. When we call callback in the form of an anonymous function it has access to the for loop and it’s i value, which we just call item, because remember, anytime we create a function and pass in parameters, at the time of the function call — arguments are saved in the parameters as new variables. Essentially var item = i. You’ll see this pattern a lot, you can rename a variable as another parameter name — so long as you are comfortable with doing that. You could still call the variable i inside the anonymous function, but perhaps item is more clear at the time of use.

We want to see the item in the array — hence item. When you start to write declarative code, it makes more sense to say what you are doing than to type out code in a literal fashion with no real meaning.

After the forEach finishes adding each item in our array to our result, we then exit the forEach function (good-bye) and see our result in the console.

Could we use this forEach method again for subtraction, multiplication, division?

Sure.

function forEach(array, callback){
    for(var i=0; i<array.length; i++){
        callback(array[i];
    }
}
var myArray = [1,2,3,4,5,6,7,8,9,10];
var result = 0;
forEach(myArray, function(item){
    result -= item //Subtraction
});
console.log(result);
function forEach(array, callback){
    for(var i=0; i<array.length; i++){
        callback(array[i]);
    }
}
var myArray = [1,2,3,4,5,6,7,8,9,10];
var result = 0;
forEach(myArray, function(item){
    result *= item //Multiplication
});
console.log(result);
function forEach(array, callback){
    for(var i=0; i<array.length; i++){
        callback(array[i]);
    }
}
var myArray = [1,2,3,4,5,6,7,8,9,10];
var result = 1; //changing here to 1 since we can't divide by 0 in math.
forEach(myArray, function(item){
    result /= item //Division
})
console.log(result);

Cool — getting it? The for loop is now buried, we don’t care for the details, we can just use our declarative function to do addition, subtraction, multiplication and division.

Can we be even more declarative?

You bet, and I love your enthusiasm!

Let’s finish up with a final exercise before I let you off into the wild to explore all kinds of other higher order functions.

Refactoring our forEach function. I don’t care about the details, I just want to just say add, multiply, subtract, or divide from the get-go when I use a function.

let arr = [1,2,3,4];

function calculate(array, operator){
    var total = array[0];
    var doCalculation = {
        "+" : function(result, item){ 
            total += item;
        },
        "-" : function(result, item){
            total -= item;
        },
        "*" : function(result, item){
            total *= item;
        },
        "/" : function(result, item){
            total /= item;
        }
    };

    function forEach(array, callback){
      for(var i=1; i<array.length; i++){
          callback(array[i]);
      }
    }

    forEach(array, function(item){
        doCalculation[operator](total, item);
    });
    //rather than just return and save in a variable, why not just console.log, 
    //that's what I'll eventually do anyway -- think declarative, think easy.
    console.log(total); 
    return total;
}

calculate(arr, "+")
calculate(arr, "-")
calculate(arr, "*")
calculate(arr, "/")

Okay so that’s a lot of nested functions. But the point is, rather than write four different functions externally, we can now bury all those functions into a higher order calculate function that is set up to do addition, subtraction, multiplication and division. We don’t need to know the details, we just want to declaratively calculate whatever we pass in as an array with a sign of our choice.

Some people might be confused by the object doCalculation so I’ll explain it. Essentially at the time of function call inside forEach, we pass in our operator as a “string”, which our object doCalculation can look up. Upon looking up the string operator "+" we passed, we see that its value in the object is function(result, item){ total += item } which basically says hey add one more to the global total inside our main calculate function. If we use use a different string operator, like "-", then it will search the object for its corresponding value (a subtract function), do the modification to the total value, and so on. Sure this could probably be even more refactored, but you get the idea!

Your Turn!

Go out into the wild now and learn these three basic higher order functions:

  • Array.prototype.map
  • Array.prototype.reduce
  • Array.prototype.filter

Simply search with your favorite search engine each item above individually and then play around with the examples you find — MDN is a good site to reference for these methods.

After studying the above methods for a few days, as an exercise, try to write each method out by yourself without reference. You will need to think about what each function “does” imperatively under the hood, then figure out how to write that imperative code out. Then bury said imperative code in a nested function, and create a higher order function that we can just call for convenience. This might be challenging, but it’s worth taxing your brain over — eventually you’ll be writing solid declarative code for others that you can hold your head up high for.

As a bonus, if you really understand higher order functions, try seeing how JQuery works under the hood too! Learning how JQuery really works is a solid field trip in higher order functions. Once you graduate, you will be a true JavaScript Ninja!