JavaScript is a language that’s great at working with functions. In JavaScript, functions are considered “first class objects”. A function is an instance of the Object type, so it can do all of the things that other objects can do. One of the more powerful things a function can do is accept another function as a parameter. You can also create functions that return new functions within their body for later use. These language constructs are what make up the concepts behind higher order functions.
A higher order function needs to do at least one of two things:
- Accept a function as one of it’s parameters
- Return a new function
Let’s take a look at examples of both. Say we have a list of names in our overly simplified program. Our program’s job is to simply say hello to every name that is in our list. Quite the friendly little app. A common approach may be to do something like this:
names = ["Darrell", "Joe", "Ryan", "Larry", "Kayla", "Sue"]
for name in names then console.log "Hello, #{name}!"
# -> Hello, Darrell!
# Hello, Joe!
# Hello, Ryan!
# ...
That’s cool, but that whole console.log part could be a lot better. Perhaps that could be wrapped up into it’s own function. Let’s call it “sayHello”
names = ["Darrell", "Joe", "Ryan", "Larry", "Kayla", "Sue"]
# the new, clean sayHello function
sayHello = (name) ->
console.log "Hello, #{name}!"
for name in names then sayHello name
# -> Hello, Darrell!
# Hello, Joe!
# Hello, Ryan!
# ...
This is a bit more flexible. At least now if we had another function, we could use it in place of sayHello in the program.
That’s an interesting concept. Maybe our program needs to do a lot of different things with names besides just saying hello. This is a great opportunity to create a higher order function that takes another function as one of its parameters. This will allow us to hide the for loop a little better as well as specify a function to use for each name in the list. We’ll call this function “withNames”. Hopefully when reading the function you’ll see why the name makes sense
names = ["Darrell", "Joe", "Ryan", "Larry", "Kayla", "Sue"]
# The new higher order withNames function that takes
# a list of names and a function as its parameters
withNames = (names, func) ->
for name in names then func name
sayHello = (name) ->
console.log "Hello, #{name}!"
withNames names, sayHello
# -> Hello, Darrell!
# Hello, Joe!
# Hello, Ryan!
# ...
Our higher order function will take any function as the second parameter as long as that function knows how to handle the list of names in some way. Let’s create another function that now says goodbye to everyone in the list and use it as a parameter in our new “withNames” function
sayGoodbye = (name) ->
console.log "Goodbye, #{name}!"
withNames names, sayHello
withNames names, sayGoodbye
# -> Hello, Darrell!
# Hello, Joe!
# Hello, Ryan!
# ...
# -> Goodbye, Darrell!
# Goodbye, Joe!
# Goodbye, Ryan!
# ...
Clearly, the power of abstracting our loop logic into a higher order function has made the program more concise, and cleaned up what would have been a lot of repetitive code.
Let’s take a look at a higher order function that returns another function. A post on the Mozilla developer website describes a way to create a function called an “adder” which adds a specified number to the number given as its argument. So, for instance, we would want our add10 function to add 10 to the number we give it
add10 2
# => 12
We could, of course just define a function that adds 10 to the given parameter, but that wouldn’t be very exciting. Let’s, instead, define a function that let’s us create any “adder” function that we want to.
makeAdder = (x) ->
(y) ->
x + y
addTen = makeAdder(10)
addTwo = makeAdder(2)
console.log addTen 2
console.log addTwo 2
# => 12
# => 4
The way this works has to do with something called closure, but that’s best saved for another post. This can be thought of simply as makeAdder allowing us to tell it the amount to be added to the new number that is used as its returned function’s parameter.
The flexibility of JavaScript’s functions provides a very nice interface for abstracting programming logic into more concise chunks of code. Higher order functions can allow for greater levels of expressivity, and can often create a more clear interface within your program. Hack around with a few simple examples to get an understanding, and these concepts will provide invaluable in your JavaScript travels.