Functions are defined as first class citizens or first class objects in JavaScript because functions are treated like variables.
This means that functions in JavaScript can be:
It is essential to understand how functions are treated in JavaScript, as they serve as a building block to understanding higher order and callback functions in JavaScript and how they work.
Higher order functions are functions that take functions as arguments and also return a function as a value.
There are a lot of built-in higher order functions provided in JavaScript. We'll take a look at some and take advantage of how functions are treated as first class citizens. We'll also create our own higher order functions.
First, let's take a look at some examples of built-in higher order functions.
Array methods are usually the first introduction of higher order functions a developer will have when learning JavaScript. These include, but are not limited to, the map, filter, forEach, find, findIndex, some, and every array methods provided by JavaScript.
These array methods or functions have a lot in common, but one of the most common feature is that they all accept a function as an argument. Below is a code snippet that demonstrates how the forEach array method works:
From the code sample above, we can see that the forEach method accepts a function as an argument which it calls on every iteration on the array. Therefore the forEach array method is a higher order function.
Another set of commonly used built-in higher order functions are the setInterval and setTimeout functions, known as timer events in JavaScript.
Each function accepts a function as one of its arguments and uses it to create a timed event.
Take a look at the code sample below to see how setTimeout works:
The code snippet above is the most basic example of how a setTimeout function works. It accepts a function and a time duration in milliseconds and executes the function after the provided duration has passed.
From the example above, This is a higher order function is printed to the console after 1000 ms, or one second.
The setInterval function is similar to the setTimeout function, just like the array methods – although it functions differently. But we can see a common pattern: it also accepts a function as one of its parameters.
Unlike setTimeout (that executes the function after the provided duration has passed), setInterval executes the function over and over again every 1000ms or 1 second.
Higher order functions are not limited to the built-in ones provided by JavaScript.
Since functions in JavaScript are treated as first class objects, we can take advantage of this behavior and build highly performant and reusable functions.
In the examples below, we'll build a couple of functions. They'll accept the name of a customer and a greeting, and then print that info to the console.
First, here is a simple function that does both of those things:
greetCustomer accepts 3 arguments: a first name, a last name, and a salutation. Then it prints a greeting to the customer to the console.
But there is a problem with this function – it's doing two things: composing the full name of the customer and also printing the greeting.
This is not a best practice, as functions should do only one thing and do it well. So we are going to refactor our code.
Another function should compose the customer's name so that the greetCustomer function only has to print the greeting to the console. So let's write a function that handles that:
Now that we have a function that combines the customer's first and last names, we can use that function in greetCustomer:
Now this looks cleaner, and each function does just one thing. The greetCustomer function now accept 4 arguments, and since one of those arguments is a function, it's now a higher order function.
You might have wondered earlier, how is a function being invoked inside of another function, and why?
Now we'll take a deep dive into function invocation and answer both of those questions.
Remember that higher order functions either take a function as a parameter and/or return a function as a value.
Let's refactor the greetCustomer function to use fewer arguments and return a function:
The last version of greetCustomer accepted too many arguments. Four arguments isn't a lot, but it would still be frustrating if you messed up the order of the arguments. Generally, the fewer arguments you have, the better.
So in the example above, we have a function called getGreetingDetails which accepts composerFunc and salutation on behalf of the inner greetCustomer function. It then returns the inner greetCustomer function, which itself accepts firstName and lastName as arguments.
By doing this, greetCustomer has fewer arguments overall.
And with that, let's take a look at how to use the getGreetingDetails function: