JavaScript Closure - What and Why?

Jessica Lee
3 min readAug 19, 2022

--

I have read and studied the concept of ‘closure’ in JavaScript multiple times, but it has been very difficult to get familiar with it.

This article is for refreshing myself about closures, but hope it could help readers too. This article refers to MDN official documentation and a book called Modern JavaScript Deep Dive published in Korea.

MDN defines a closure as:

the combination of a function and the lexical environment within which that function was declared.

If you are not familiar with what a lexical environment is:

A lexical environment is a component of the execution context where manages identifiers and values binding to the identifiers, and records reference to the outer scope.

In JavaScript, a function’s outer scope, that is, reference value of the “outer lexical environment reference” in its lexical environment is decided based on where (the environment) the function is declared, and it is decided when the function declaration is evaluated and its lexical environment is formed. This is called a lexical scope which means it does not change regardless of where the function was called.

So, what does this mean?

We can call an inner function a closure when it can still refer to the outer function’s variables even when the outer function’s lifetime has completed.

As the earlier definition of a closure states, “the lexical environment within which that function was declared” points to the scope where the function is declared, that is, its outer scope which means the lexical environment of the execution context.

const x = 1; 

function outer () {
const x= 10;
const inner = function() {
console.log(x)
};
return inner;
}
const innerFunc = outer();
innerFunc(); //returns 10

In the example above, outer function’s lifetime will be completed once it returns inner function, however, when we call innerFunc, we can still access the x variable declared in the outer function.

this is because the outer scope of the inner function has already been saved to the inner function’s environment internal slot when the inner function was declared. In other words, even when the outer function has been popped from the execution context stack and its lifetime has completed, its lexical environment is preserved because the inner function refers to it as the outer lexical environment reference.

Theoretically, all functions are closures. However, generally, we don’t call a function a closure if:

  1. a function does not refer to any variable in the outer scope.
  2. a function refers to variables in the outer scope, but its lifetime is shorter than the outer function.

Finally, what can we use a closure for?

We use a closure to safely save or change a state. We can achieve information hiding and allow a specific function to change states through a closure. Let’s take a look at simple examples.

Example 1

let num = 0;const increase = function () {
return ++num;
}
console.log(increase()); //return 1
console.log(increase()); //return 2
console.log(increase()); //return 3

The example above will give us the desired result, but it is not a good code because the variable num can be accessed anywhere throughout the code and its state can change. We want to make the variable modified by a specific function only.

Example 2

const increase = function () {
let num = 0;
return ++num;
}
console.log(increase()); //return 1
console.log(increase()); //return 1
console.log(increase()); //return 1

In this example, we have made increase function the only way to modify variable num . However, the result is not what we want because the num gets declared to 0 every time the function is called.

Example 3

const increase = (function () {
let num = 0;
return function () {
return ++num;
}
}());
console.log(increase()); //return 1
console.log(increase()); //return 2
console.log(increase()); //return 3

In this final example, the immediately-invoked function will return a closure and assigns to increase which remembers its outer scope that contains variable x. So, even if the the immediately-invoked function returned and its lifetime has completed, because the returned closure has been assigned to increase, it can still access to the outer scope’s variable.

Also, because the immediately-invoked function gets called only once, x will not be re-assigned to its initial value of 0, and because it is a private variable which cannot be referred from the outside, we can achieve safe programming.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response