Severin Perez

An Introduction to First-Class Functions in JavaScript

June 24, 2018

JavaScript, for all of its power and expressiveness, is a language that refuses categorization. Some prefer to use it in the object-oriented style and others in the functional style. And the mere fact that it can be used in either tells us something about JavaScript’s dynamism. JavaScript is a flexible language that provides a wealth of features that, if well understood, can be leveraged in powerful ways. Previously, we explored object design patterns in JavaScript, so in this post let’s take some time to explore the language’s functional side.

One of the most dynamic features of JavaScript is that it has first-class functions, meaning that functions are treated like any other first-class object—they can be stored in variables, passed around, returned from other functions, and even hold their own properties. For the JavaScript programmer this means that you can take advantage of powerful design patterns such as higher-order functions, partial function application, callbacks, and more. First-class functions are a vital part of the JavaScript landscape, so, let’s take a closer look and see what they’re all about.

Attributes of a First-Class Function

A first-class object, sometimes referred to as a first-class citizen, is an object that supports all of the operations generally allowed to other objects. In fact, JavaScript functions are themselves types of objects. A first-class function can thus be expected to support the same operations we would expect from other objects. So what are these operations? Generally, first-class objects can:

  • Be stored in a variable;
  • Be passed as arguments to functions;
  • Be returned by functions;
  • Be stored in some data structure; and,
  • Hold their own properties and methods.

As an example, consider the following snippet, in which we shall attempt each of the above-described operations on a function.

// Function definition and invocation
function speak(string) {
  console.log(string);
}
speak("Hello");                     // logs "Hello"

// Store in a variable
var talk = speak;
talk("Hi");                         // logs "Hi"

// Pass as an argument to a function
// Return from a function
function functionReturner(fn) {
  return fn;
}
var chat = functionReturner(talk);
chat("Good Morning");               // logs "Good Morning"

// Store in a data structure
var myFuncs = [talk];
myFuncs[0]("Good Afternoon");       // logs "Good Afternoon"

// Owns properties
talk.myProperty = "bananas";
console.log(talk.myProperty);       // logs "bananas"

The above snippet shows us that functions are indeed more flexible that you might first have imagined. Let’s briefly walk through each operation.

Storage in a Variable

On line 2 we declare our function speak() and subsequently demonstrate its invocation on line 5. So far things are looking pretty standard. Then, on line 8 we define a variable talk and assign in the value ofspeak. When we call talk as a function on line 9 we get the same functionality as when calling speak! This shows that you can store a function in a variable. Not only that, but in this case both speak and talk refer to the same function, and the expression speak === talk will return true.

Passage as an Argument to a Function; Return Value from a Function

On line 13 we declare another function, self-consciously called functionReturner, which serves the somewhat silly purpose of receiving a function as an argument and simply returning it. And indeed, on line 16 when we pass functionReturner our function talk as an argument and assign its return value to the variable chat, we get exactly the same functionality as we did with talk or speak. This is a very arbitrary example, but it shows that functions can indeed be passed as arguments to other functions, and that they can be the return value from other functions too— just like any other first-class object.

Storage in a Data Structure

Not only can functions be stored in variables, but they can also be stored in data structures. In this example, on line 20, we store our function talk inside an array called myFuncs. On line 21, when we attempt to access myFuncs[0], which we expect to be a function, and call it, we do in fact get the functionality we are expecting. A function can similarly be stored on other data structures, such as an object, in which case we generally refer to it as a method of that object.

Owner of a Property

And finally, on line 24 we assign our function talk an arbitrary property called myProperty and store the value “bananas” inside it (because, you know, why not?) Just like with any other object, we can directly access this property and we do so on line 25.

Uses of a First-Class Function

So, we know that functions in JavaScript are first-class citizens. Now what do we do with that knowledge? This is where the fun part starts. First-class functions give us a wide variety of flexible and powerful design patterns. These patterns let us write more readable, more dynamic, and more concise code. Let’s take a look at a few.

Higher-Order Functions

A higher-order function is one that either has a function as a parameter, or returns a function. In other words, higher-order functions do work on other functions. The classic example of higher-order functions are built-in functions that we use every day to manipulate JavaScript objects and data structures. These built-in functions do some kind of work such as iteration or transformation. Often, we supply such built-in functions with anonymous functions as callback arguments, but we can also pass in existing functions. Consider the following:

var myNums = [1, 2, 3, 4, 5];

function doubleNum(num) {
  return num * 2;
}

// Built-in Array.prototype.map function, using anonymous function argument
var doubledNums = myNums.map(function(num) {
  return num * 2;
});
console.log(doubledNums);           // logs "[2, 4, 6, 8, 10]"

// Built-in Array.prototype.map function, using named callback argument
var otherDoubledNums = myNums.map(doubleNum);
console.log(otherDoubledNums);      // logs "[2, 4, 6, 8, 10]"

In this snippet, we first define a variable myNums which contains an array of numbers. We also define a function doubleNum which accepts a number as an argument and returns double the value of that number. We then demonstrate higher-order functions using built-in function Array.prototype.map, which iterates over an array, transforming each value and returning a new array with those values. On line 8, in the first example, we provide map with an anonymous function that doubles each value in the array. On line 14, we pass map our predefined function doubleNum, which it then uses in the transformation process. In both cases we get the same result.

Partial Function Application

Of course, we don’t have to rely on built-in JavaScript higher-order functions. We can also write our own! One of the most powerful patterns for this is the idea of partial function application. In this pattern, we write a function that accepts another function as a parameter. The function then returns a new function that has the same functionality as the one we provided as an argument but with some value pre-applied to it. This can be a somewhat tricky idea to get your head around, so let’s check it out in the code.

function applicator(fn, val) {
  return function() {
    fn(val);
  };
}

function speak(string) {
  console.log(string);
}

var sayHello = applicator(speak, "Hello");
sayHello();                         // logs "Hello";

On line 1 we define our own higher-order function called applicator, which takes a function and some value as its arguments. applicator then returns a new function, which itself calls the previously provided function using the previously provided value as its argument. We do just this on line 11 where we define a variable sayHello and assign it the return value of applicator, passing in the speak function we used earlier and the value “Hello”. This gives us a function that always logs “Hello” when called (as in on line 12.)

So why is this so powerful? Well, not only does it let us create new functions with pre-applied values, but we can do so over and over, as much as needed. In this case we made a sayHello function (which can say “hello” without any parameters). But if we wanted we could use applicator to make a sayHi function, a sayGoodbye function, or whatever else we want.

Asynchronous Functions

Another common use of first-class function is when an asynchronous callback is necessary. This is often the case in web applications where some function must wait to be called until a server has returned some value or a promise has been fulfilled. We won’t get into that here but we can simulate delaying a function call using the built-in function setTimeout, which accepts a callback and a delay as values. Here is an example using our trusty speak function.

function speak(string) {
  console.log(string);
}

var delayedFunction = function(fn) {
  return function(val, delay) {
    setTimeout(function() {
      fn(val);
    }, delay);
  };
};

var delayedSpeak = delayedFunction(speak);
delayedSpeak("I'm late!", 1000);      // logs "I'm late" after a 1 second delay

In this snippet, on line 5 we define a new higher-order function called delayedFunction, which accepts a function as a an argument and then returns a new function, which accepts a value and a delay. The new function uses setTimeout to wait delay length before executing the original function we provided to delayedFunction with the provided value as its argument. We then use delayedFunction on line 13, passing in our speak function, to create a new function called delayedSpeak. Now we can use speak with some delay! Here we have not only used first-class functions, and higher-order functions, but also seen how to asynchronously execute our code.


And there you have it! A short introduction to first-class functions in JavaScript and how you can use them to make your code more flexible and concise. I hope you have enjoyed this introduction. Happy coding!


Note: This article was originally published on Medium.


You might enjoy...


© Severin Perez, 2021