Skip to content

A Drive Through Javascript Closures

📅 2020-11-16

Closures are a fundamental concept to Javascript but can be difficult for beginners to understand. To alleviate this, we will define the basic concept and then apply this abstract concept to something familiar like a car.

Basic Concept

A closure is a combination of a function and the outer scope. The outer scope can refer to variables or other functions.

A simple example would be:

var outerVar = "value";

function enclosedFunc() {    
  console.log(outerVar);
}

enclosedFunc()
// value

Here enclosedFunc is the enclosed function that prints outerVar. The outer scope of enclosedFunc is the global scope, which includes outerVar. When executing enclosedFunc, it has access to outerVar and prints “value”. The example shows a closure in the simplest form. A function is a closure. Thus, every function is a closure. The function does not need to be nested to be a closure. However, this does not show how closures can be useful. The following analogy will demonstrate a potential use-case for closures.


Analogy

old car in a restoration workshop

Closures can be used like private functions. When a closure is nested inside an outer function, it has access to the variables and functions of the outer function. This is true even after the outer function has finished executing.

Let’s use a car as an analogy:

makeCar diagram with car sitting in a factory

A car closure sitting in the factory closure

Here is the car, represented in Javascript:

function makeCar() {
    place = 'factory'

    function car(destination) {
        console.log(`Started at ${place}`)
        place = destination
        console.log(`Arrvied at ${place}`)
    }

    console.log(`Constructed at ${place}`)

    return car
}

There are two closures here:

  1. makeCar
  2. car

The outer makeCar closure creates each instance of a car.

The inner car closure allows the car to drive to a destination. Since car is nested inside of makeCar, it has access to the place variable.

In our analogy, we will focus only on the car closure, as the function represents the body of the car. This would be things like the engine, tires, and doors.

The place variable represents the surrounding location of the car, not a component of the car itself. The ability to move allows the car to change its surrounding location. Thus, the place variable fits into the outer scope of the car closure.

lone road


Now we will make a car and drive to a destination.

carFL = makeCar()
// Constructed at factory

carFL('miami')
// Started at factory
// Arrvied at miami

The carFL variable is initialized to the car function with the place variable initially set to “factory”. Executing carFL updates the place variable from “factory” to “miami”.


When making two cars, each one is able to drive to their own destinations.

carFL = makeCar()
// Constructed at factory

carWA = makeCar()
// Constructed at factory

carFL('miami')
// Started at factory
// Arrvied at miami

carWA('seattle')
// Started at factory
// Arrvied at seattle

carFL('jacksonville')
// Started at miami
// Arrvied at jacksonville

Even though both carFL and carWA closures have a place variable, their scopes encapsulate their own version of it.

makeCar diagram creating car objects

Both cars start in the “factory”. Then carFL drives to “miami” and “jacksonville”, while carWA drives to “seattle”. This shows that a car driving to one destination will not affect the other cars, even though they all originated from makeCar.

Also note that when executing carFL(‘jacksonville’), it starts at “miami” and was not reset to “factory”.


Conclusion

Like cars, closures are a useful tool in Javascript. There are many use cases for closures and understanding them is an important part of our journey to become better developers.

For further reading about closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures