Closures are one of the key concepts in Javascript, that a javascript developer should know. It is a complicated topic that is sometimes difficult to grasp, you require practice to get better in the concept of closures. To understand closure we need to understand several concepts in Javascript which we will go through one by one.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
-By MDN Web Docs
So basically closure means where the given function is enclosed. Whenever a function is created inside javascript a closure is also created for that function. Closures give a reference to the parent environment in which the function is defined so that the function has access to its parent's variables and functions. But what is this parent environment and why it is called a Lexical environment?
Lexical Environment
So in simple terms, a Lexical means "in the hierarchy". So where does this current function lie in the hierarchy of our current code? Lexical Environment is a combination of the local memory of a function and (closure) reference to its parent lexical environment. Now this is getting complicated as closure and lexical environment sounds to be the same. Let's take an example to better understand them.
function Outer()
{
var a = 100;
function Inner()
{
console.log(a);
}
Inner();
}
Outer();
Here we have created an Outer function and inside it, we have created an Inner function. So as we know inside the Javascript call stack first global execution context is created, and inside this, we will have two parts memory allocation and code execution. So while allocating memory if you see we have only the Outer function in a global context for which memory is allocated. But still by calling we can print the value of a which is 100. How?
Let's take a look from the browser by debugging what is happening. The first Outer function is invoked in line 10. So it will create its separate execution context, here it will allocate memory for variable a and function Inner. Now it will start executing the code. Once it reaches line 8 it will invoke the Inner function, and now the Inner function will create its execution context and push it into the call stack. We can see the Callstack at the bottom left of how all functions are there inside the call stack, Anonymous being the global execution context.
Once the code reaches line 6 it will try to access the value of variable a. So first it will try to look for the definition of variable an inside the local memory of the Inner function, it is not there. Now Lexical environment of function Inner. So if you see at the bottom right of the above Image you will see a tab highlighted as scope. So under this tab whatever names we have it represents the Lexical environment of the Inner function. Here you can see it has Local meaning access to all of its local variables and functions, then Closure (Outer) meaning a reference to its parent's lexical environment and at last Global which is a reference to the lexical environment of its parent's parent lexical environment which is the global scope. So because of this reference to its parent's lexical environment Inner function will be able to access all the variables and functions that are defined in its parent lexical environment. That's why the Inner function can access the value of variable a and it is not printing not defined in the console.
Similarly in the lexical environment of Outer function, we will have Local and Global. And for the case of Global, we will have Local and null because for the case of Global, it points to null as it does not have any parent. So above example clearly shows the difference between lexical environment and closures. The lexical environment is a combination of the local memory concerning all the parent lexical environments in the hierarchy. And closures are nothing but these references to the parent's lexical environment.
Scope in Javascript
Now what is scope, scope is directly related to the lexical environment of the function. The scope is where a variable is accessible inside the code. The lexical environment is nothing but scope. There is another concept involved which is called a scope chain. We have just seen this concept. The scope chain is looking for a variable inside the parent scope in the hierarchy. Let's say we are accessing any variable of global scope in the Inner function. So first the Inner function will look in its local memory, then in the scope of the Outer function, and finally, it will search in the scope of the global context. This chain is basically what we call a Scope chain.
Closures Examples
Example 1:
In Javascript, we can return functions, as they are treated as objects inside Javascript.
function Operations()
{
function Multiply(a, b)
{
return a*b;
}
function Addition(a,b){
return a+b;
}
function Subtraction(a,b){
return a-b;
}
function Division(a,b){
return a/b;
}
return function CallMe(x,y,z){
switch(z){
case 1:
return Multiply(x,y);
case 2:
return Addition(x,y);
case 3:
return Subtraction(x,y);
case 4:
return Division(x,y);
}
}
}
let dummy = Operations();
console.log(dummy(2,3,1));// 6
console.log(dummy(2,3,2));// 5
console.log(dummy(6,3,3));// 3
console.log(dummy(6,3,4));// 2
Example 2:
let count = 0;
(function immediate() {
if (count === 0) {
let count = 1;
console.log(count); // 1
}
console.log(count); // 0
})();
Example 3:
for (var i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // 3 3 3
}, 1000);
}
Example 4:
for (var i = 0; i < 3; i++) {
setTimeout(function log(j) {
console.log(j); // 0 1 2
}, 1000,i);
}
Uses of Closures
Various uses of Closures inside Javascript are why it becomes a very important concept to understand. You need to have a good understanding to understand the working of code inside Javascript.
Module Design Patterns
Using private variables and methods
Currying Functions like Once
Memoization
Maintaining state in the async world
setTimeouts
Iterators