DEV Community

CritJen
CritJen

Posted on

Higher Order Functions

After attending a functional programming meetup I've decided to explore some functional programming concepts in JavaScript. So for the first of many I'm exploring higher order function.

So what are higher order functions?

A higher-order function is a function that either takes another function as an argument or returns a function. So before we break that down it's important to note that:

Functions are first-class objects

This means that functions are treated as objects in JavaScript. That's why you can store them in variables and pass them around. It's this feature of the language that allows us to create higher order functions!

So you can store them in variables

const catSound = function meow() { console.log("Meow") }

You can then pass these variables around. If we needed a more personalized function for our beloved cat Mr. Whiskers that would be easy enough:

const mrWhiskersSound = catSound

So now if we invoke mrWhiskersSound

mrWhiskersSound()

"Meow" will be logged to the console just the same as if we had invoked our meow function.

You can also store a function in an object

let dogSound = { bark : function(){} }

And you can store a function in an array

let fishSound.push(function blurp() {})

Functions can be passed in as an argument

You can pass a function into another function as an argument.

function dangleString() {
    console.log("Dangles a piece of string high in the air");
}

function fetch() {
    console.log("Throws the stick");
}

function play(pet, dangleString, fetch){
   if(pet === "dog"){
      fetch();
   } else if (pet === "cat"){
      dangleString();
   } else {
      return "Back away slowly from unknown creature";
   }
}

Here we're defining two separate functions, dangleString and fetch. We're then passing both of these functions in as arguments to our third function play. If we then invoke the play function and pass in a cat as our pet argument the dangleString function will execute. If we passed in a dog instead the fetch function would execute, you get the idea. Since play is accepting functions as arguments it's a higher-order function. We did it!

There was also a second scenario for higher-order functions which is when a function returns a function.

function badExample() {

   function learn() {
      console.log("I'm leaning stuff");
   }

   return learn;
}

So this isn't the most useful example but it demonstrates the concept well enough. The return value from the badExample function call will be the learn function. So you could save that return value into a variable and invoke it later.

const learnFunc = badExample();
learnFunc();

Here our badExample function call returns our learn function and we're storing this return value in a varibale called learnFunc. When we invoke learnFunc later on it will execute the learn function and "I'm learning stuff" will be printed to the console. Yet another higher-order function! We're super good at this.

So that all seems pretty clear but doesn't really demonstrate how incredibly useful higher-order functions can be. So let's see at least once example of why this is useful.

JavaScript has a lot of really useful built-in higher order functions. Map, filter, and reduce are some very common examples that you've likely used before. So whether or not your realized it, you were using a higher order function.

Map

The map method is a built-in higher-order function on the Array prototype. That's certainly a mouthful. Put more plainly, anytime you create an Array in JavaScript map is one of several actions you can automatically take. The lovely JavaScript people have already written the logic for us so we don't have to. It's worth noting that since it's part of the array prototype this is an option we have for interacting with arrays but not other datatypes.

When you use map you pass in an array and a callback function as arguments and map creates a new array for you by going through every element in the array and performing whatever function you passed in.

Callback function: a function passed in as an argument to a higher-order function that will be executed once all the other operations have been completed.

So let's say we're faced with the age old problem of adding two to every number in an array (happens to me all the time).

Let's save ourselves all the for loop nonsense and use map.

const nums = [1, 3, 4, 6]

const addTwo = num => num + 2

const newNums = nums.map(addTwo)

//newNums = [3, 5, 6, 8]

So we start with an array on numbers (nums). Since it's an array we can use map on it and we just need to pass in our callback function. Map then goes through and invokes our addTwo function on each elements in nums. Since I used an arrow function without curly braces the new value is automatically returned in addTwo. We could also define our callback function in line.

const nums = [1, 3, 4, 6]
const newNums = nums.map(num => num + 2)
//newNums = [3, 5, 6, 8]

So this is a great example of a really useful higher-order function as well as passing around functions as arguments. I won't go into examples of reduce and filter this week since this is getting a little long. But maybe next week!

What else should I look into as I try to get a better grasp on functional programming in JavaScript? I was looking into factory functions and they seem cool but I don't want to get too ahead of myself.

Top comments (0)