Closures are a relatively new concept in JavaScript and they tend to be a little difficult for people to understand. There have been times when people use closures, but don’t really know that they’re using one. The docs on MDN are easy to get started with, but for a better understanding of the concept, you must get your hands dirty with some code. Today, we are going to be looking at closures in JavaScript and understand them once and for all.
Understanding the scope of execution
Before we dive deep into closures it is important to understand the scope of execution of a program. Imagine you have a program with 10-20 lines of code without any functions. Just a few lines of code, plain and simple. In this scenario, we just have one single scope of execution, and that is the global scope.
Are you sure you're getting this? Click the correct answer from the options.
What would be the output of the following program?
1let a = 2;
2const sum = () => {
3 let a = 5;
4 return a + 20;
5}
6console.log(a + sum());
Click the option that best answers the question.
- 27
- 25
- undefined
- NullPointerException
What if we had a function that is called in between the program? This would result in the creation of a local scope (for the function). A stack data structure is used here to store the local scope and it is added on the top of the stack. Remember that this local scope has its own set of variables and it ends when there is a return statement or the function is closed.
Now, what happens when the local scope of execution ends? Here, it is the responsibility of the parent scope (in our case, the global scope), to handle the return variable and continue on with its execution. The local scope of execution that was added to the stack is popped off and destroyed completely.
Functions inside functions
This is a very important concept to understand for fully understanding closures. Take a look at the example code below. It has a method called scopeCheck()
inside which there is another function called innerScopeCheck()
. Outside the function, there is a variable called globalScope
, another variable that gets the return value of the scopeCheck() method and a couple of console.log()
statements.
xxxxxxxxxx
const scopeCheck = () => {
let localScope = "LOCAL";
const innerScopeCheck = () => {
let innerLocalScope = "INNER LOCAL";
return globalScope + " { " + localScope + " { " + innerLocalScope + " }} ";
}
return innerScopeCheck;
}
let globalScope = "GLOBAL";
let thisIsAFunction = scopeCheck();
console.log(thisIsAFunction);
console.log(thisIsAFunction());
What did you infer from this? There are two important points to be inferred. First, the return value of the scopeCheck() method is in fact another method (the innerScopeCheck() method). The second is that the variable declared in the global scope is available even inside the inner function, but the other way around is not possible. If you try printing the variable innerLocalScope outside the innerScopeCheck() method, it will throw an error.
Try this exercise. Click the correct answer from the options.
What would be the output of the following code snippet?
1const scopeCheck = () => {
2 let localScope = "LOCAL";
3 const innerScopeCheck = () => {
4 let innerLocalScope = "INNER LOCAL";
5 return globalScope + " { " + localScope + " { " + innerLocalScope + " }} ";
6 }
7 console.log(innerLocalScope);
8 return innerScopeCheck;
9}
10//let globalScope = "GLOBAL";
11//Function returning function
12let fun1 = scopeCheck();
13console.log(fun1());
Click the option that best answers the question.
- undefined
- scopeCheck() is not defined
- GLOBAL { LOCAL { INNER LOCAL } }
- ReferenceError: innerLocalScope is not defined
Let's test your knowledge. Click the correct answer from the options.
What would be the output of the following code snippet?
1const scopeCheck = () => {
2 let localScope = "LOCAL";
3 const innerScopeCheck = () => {
4 let innerLocalScope = "INNER LOCAL";
5 return globalScope + " { " + localScope + " { " + innerLocalScope + " }} ";
6 }
7 return innerScopeCheck;
8}
9let globalScope = "GLOBAL";
10console.log(scopeCheck()());
Click the option that best answers the question.
- Error
- scopeCheck() is undefined
- GLOBAL { LOCAL { INNER LOCAL } }
- None of the above
Let’s get some closure
So far so good. Let’s take a look at a new example to understand closures. This will look very similar to the examples we’ve seen before with very minimal changes.
1const scopeCheck = () => {
2 let b = 20;
3 const innerScopeCheck = () => {
4 let a = 10;
5 let ret = a + b;
6 b++;
7 return ret;
8 }
9 return innerScopeCheck;
10}
11let fun1 = scopeCheck();
12let fun2 = scopeCheck();
13
14console.log("Function 1 first execution: " + fun1());
15console.log("Function 1 second execution: " + fun1());
16console.log("Function 1 third execution: " + fun1());
17
18console.log("Function 2 first execution: " + fun2());
The output of the following code snippet will be as shown below.
1Function 1 first execution: 30
2Function 1 second execution: 31
3Function 1 third execution: 32
4Function 2 first execution: 30
Let’s quickly run through each run of the function’s execution. In the first run, variable b is created inside the scopeCheck() method, it is added with the variable 10 which is created inside the innerScopeCheck() method. They are both added and assigned to the ret
variable. After this, we increment b
by 1 and then return ret. In the last line of the scopeCheck() method, we return the innerScopeCheck() method.
We have two variables fun1
and fun2
each with the return values from the scopeCheck() method. Ideally, when we execute fun1 three times, the output should be 30 right? Why is the incremented value of b getting added to the subsequent executions? That is the work of a closure.
By definition, a JavaScript closure ensures that the variable is a combination of a function along with references to its surrounding state. To understand this a little more clearly, we will make use of the Inspect command in Google Chrome. The below code snippet is a slight modification of the previous one.
xxxxxxxxxx
const scopeCheck = () => {
let b = 20;
const innerScopeCheck = () => {
let a = 10;
let ret = a + b;
b++;
return ret;
}
return innerScopeCheck;
}
let fun1 = scopeCheck();
let fun2 = scopeCheck();
console.dir(fun1);
Let's test your knowledge. Fill in the missing part by typing it in.
Identify the missing scope: global, local, ___
Write the missing line below.

1const scopeCheck = () => {
2 let b = 20;
3 const innerScopeCheck = () => {
4 let a = 10;
5 let ret = a + b;
6 b++;
7 return ret;
8 }
9 return innerScopeCheck;
10}
11let fun1 = scopeCheck();
12let fun2 = scopeCheck();
13
14console.log("Function 1 first execution: " + fun1());
15console.dir(fun1);
Following the same process as we did before, let’s inspect the output on the console. This is where the concept of closures become crystal clear. If we went by the conventional way of executing a method, we would’ve thought variable b would be created each time the method is executed. But with the closure scope, each time the innerScopeCheck() method is executed, it checks for the value of b in closure scope and finds the updated value there, and uses it. That is why we see an increment in the value with each execution of the fun1() method.

We hope you have understood the concept of closures in JavaScript. They are sometimes tricky to get a hang of. But as soon as you understand it completely, you will wonder how can it be done any other way.
One Pager Cheat Sheet
Closures
are relatively new and potentially confusing, but with practice and the help of MDN docs, we can finallyunderstand
them!Understanding the Scope of Execution
is essential to properly utilizeclosures
, as a programwithout functions
will only have oneglobal scope
.- The program outputs 27 because the
console.log()
statement references the initial declareda
value before the sum function changes it. - A
stack
data structure is used to store a newly created local scope when a function is called, which ispopped off
the stack and destroyed when the scope of execution ends. - Understanding nested functions and their ability to access
globalScope
variables is essential for fully comprehending the concept ofclosures
. - The
variable
declared in theglobal scope
is available inside the inner function, but the other way around is not possible and will throw an error. - The
ReferenceError
thrown is due to innerLocalScope not being accessible from the global scope, as it is scoped to the innerScopeCheck() method. - The output of this code snippet is determined by the scope of the variables used in the
innerScopeCheck
function, withinnerLocalScope
being limited in scope. - The code snippet demonstrates the concept of
closure
by showing how an incremented value of a variable can be "remembered" across subsequent executions of a function. - A JavaScript closure combines a function with its
surrounding state
to create a new entity, which can be further investigated using theInspect
command in Google Chrome. - A JavaScript
closure
is a function combined with thelocal
scope in which it was declared and is maintained after the outer function has finished executing. - Closures offer powerful flexibility to remember the associated environment of an
innerScopeCheck()
method to have access to changed values of variables and utilize it in code, as demonstrated in thisscopeCheck()
example.