JavaScript Closures

Part 1: The Basics

Closures, very mysterious

This post was inspired by one of my favorite JavaScript YouTubers, Mattias Petter Johansson, MPJ for short. MPJ hosts the Fun Fun Function channel on YouTube (currently on hiatus). He is very experienced and ventures into new and sometimes difficult territories consistently. He is entertaining and smart. Here is what he said about closures…

Closures is this really tricky subject … and it actually took me several years into JavaScript before I really truly understood what was going on. — MPJ (Closure exposure therapy — Exploring closures in JavaScript with friendly live mob programming)

MPJ. Ace programmer.

Okay, so closures sound a bit tricky. Like many aspects of programming, we might understand this one intuitively. Let’s take a deep breath…

…and start at the beginning. According to Mozilla, a JavaScript closure is defined as…

The combination of a function bundled together (enclosed) with references to its surrounding state. In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

Whoa. This definition immediately starts getting into functions within functions, making my head spin in the process. We will get to that in a bit.

Right now, the basic idea to understand is that JavaScript functions have access to the variables that are in scope when the function is invoked. For example, consider this snippet:

Notice that sayCatchPhrase() function is invoked without any argument. Yet, it has access to the the global variable, alterEgo, which is defined outside of the sayCatchPhrase() function. Because of closure, alterEgo is available inside of sayCatchPhrase().

sayCatchPhrase() encloses alterEgo

If we did not want to rely on closure, we would need to pass alterEgo as an argument to the function instead, maybe like this:

Consider the following changes to the original example. First we assign alterEgo the value, ‘Superman’. Then, the sayCatchPhrase() function is defined, then alterEgo is reassigned to ‘Spiderman’ and finally the sayCatchPhrase() function is called. Who’s job is it?

The console.log from sayCatchPhrase() reports Spiderman even though the value was reassigned after the function was defined. This is because the sayCatchPhrase() function does not take snapshot of the values in scope at the time it is declared or anything like that. The value of alterEgo inside the sayCatchPhrase() function will reflect the current value of alterEgo when the function is invoked. At the time the sayCatchPhrase() function is invoked above, the value of alterEgo is ‘Spiderman’.

Wow, it actually happened back in 1976

At first thought, it might seem that closures could encourage the use of global variables in a JavaScript. For example, a programmer might think to set up some global variables at the beginning of a script. Then, because of closure, the functions within the script will all have access to the global variables and can change them. However, the use of global variables is bad practice and slower. The use of global variables can become buggy quickly as variable references clobber each other and values get reassigned unknowingly/accidentally. For more arguments against the use of global variables, check out this post.

Interestingly, closures can actually help prevent the use of global variables because functions in JavaScript are said to be “first class citizens”. Being a first class citizen means that in JavaScript, functions can be stored in variables, passed to other functions as arguments, and returned from other functions as values.

To see how this relates, we’re going to return a function from a function and assign it to a variable. Because of closure, the function returned will have access to variables inside the outer function.

Take the following script, for example.

The variable, number is available to the returned anonymous function from the countdown() function because of closure. However, number is not available outside of the function. For example if we try:

The number variable is effectively private to the countdown function and cannot be accessed throughout the script. Using this pattern, we can write functions that keep track of changing variables and the use of global variables can be avoided.

In the next post, we will go deeper and look at some common use cases for JavaScript closures.

Fun Fun Function
Global Variables Are Bad
Closures — Part 5 of Functional Programming in JavaScript
Closure exposure therapy — Exploring closures in JavaScript with friendly live mob programming
JavaScript Functions are First-Class Citizens