What are closures?

What are closures?

No, it's not a pop song

I first heard mention of closures in JavaScript in a YouTube video I watched about interview questions a while ago. I was curious about what closures were and I did a little research on the topic. What I learned was enough to understand the basics of what closures were but didn’t do enough to explain the intricacies behind them. So recently, I picked interest and I have decided to share what I learned. But to understand closures, we first need to understand two essential concepts in JavaScript; execution context and lexical scope.

Execution context

An execution context is an abstract environment where the JavaScript code is evaluated and executed. When the global code is executed, it’s executed inside the global execution context, and the function code is executed inside the local execution context of that function.

blogimg1.png

Let us consider the block of code above. When the script is run, a global execution context is created. Any variable declared within this context is referred to as a global variable. Now how does JavaScript handle a function call? When the function greet() is called, JavaScript creates a new local execution context for the function. Any variable declared within this context is known as a local variable.

When the function execution is complete, the local execution context is destroyed, and all local variables declared within are no longer available to the program.

blogimg2.png

Consider the block of code above. The function outer() returns a function inner(). The function outer() is assigned to a constant, sum. We would be expected that when the function stored in the constant is called, it would return undefined. However, it returns 3. Why is that? This brings us to the second concept we have to understand, lexical scope.

Lexical scope

A lexical scope (static scope) refers to the availability of variables, functions, and objects based on the position of their declaration in the source code. A variable’s lexical scope is its definition space, the place in which it was created. Only code within a variable’s lexical scope can access it. Each script has its lexical scope, known as the global lexical scope. Each block of code you create is assigned a lexical scope object.

Each lexical scope object stores two key properties, the environment of the block of code, which contains the variables within the function itself, and a reference to the lexical scope of its parent’s environment. This reference gives the block of code access to all variables in its parent’s scope, whether or not the function was invoked inside or outside the scope in which the variables were created, and makes it appear as though the function remembers the environment and the variables defined within. Looks good in theory, now let’s visualize this concept.

blogimg3.png

Let us consider the block of code above. The function greet() is assigned a lexical scope object, which stores all the variables within the function and references the outer lexical scope, which is the global scope. The global scope object in turn references the variable greeting and the function greet() and references null, as there is no outer lexical scope. When the function greet() is called and finishes execution, the lexical scope of that function is removed from memory and therefore, the variables declared within greet() cannot be used outside of it. But is it possible to use variables declared in the outside lexical scope in a function?

Let us go back to the previous example. In this example, we were able to access the variable a which was declared outside of the function inner(). How did we do that? When you access variables, they are sought from the lexical scope of the function in which they were accessed. If the variable is not found, JavaScript continues the search in the outer lexical scope. In this way, the inner() function has access to the outer() function’s variables even after the outer() function has finished executing. This feature is what is known as a closure.

Closure

A closure is a feature in JavaScript where an inner function has access to the outer (enclosing) function’s variables (its lexical scope). It can also refer to the function that has access to its outer function’s scope even after the outer function has returned. Generally speaking, a closure possesses three scope chains, which are the variables it has access to, and they are:

  • The variables defined within the function itself
  • The variables defined in the outer function(s) and
  • The variables defined in the global scope

blogimg4.png

Let’s take a look at how this code runs. The returned inner() function tries to access the constant a. As the definition of constant a is not present in the lexical scope of the inner() function, the search is continued to the lexical scope of the outer() function. Since the constant also isn’t present in this lexical scope, the search moves to the outer lexical scope, which is the global scope, and the constant definition is eventually found. It repeats this same process for constants b and c.

Conclusion

Today we learned what closures are and how they really work in JavaScript. Closures are an important concept in JavaScript and every JavaScript programmer should learn about them. It may be a difficult concept to learn, but understanding it would make it easier to spot closures and save you a lot of time debugging.

Your favorite dev, Bilal.