The best part about using closures is that with the help of closures callbacks, event handlers, and high-order functions can access outer scope variables. Other than that closures are one of the most important parts of functional programming in javascript and it is also asked in interviews quite a lot of times.
Closures are used everywhere in javascript but most people still find it difficult to understand. If you are also in that category then this article is a must-read for you as we will be explaining all the in-depth concepts of closures in javascript.
In this article first of all I will start with the fundamental terms like scope and lexical scope. After you have grasped the concept of scope and lexical scope you will be able to understand closures very easily.
Before starting the article my only suggestion to you would be that get a good grip over the scope and lexical as without it you cannot understand closures in javascript.
1. The ScopeÂ
Whenever you define a variable it is known to exist within some boundaries. For example, if a count variable makes sense inside the counter() function as an internal detail of the function. Outside of the counter() function, the count variable is useless.
In simple words, we can say that the accessibility of the variable is managed by scope. You can freely access the variable defined within its scope but outside the scope the variable is inaccessible.
The scope is generally created by a function or a code block in javascript.
Let us see with the help of an example how scope works in javascript.
Example :Â
function counter() {
// The function scope
let count = 20;
console.log(count); // logs 20 to the console
}
counter();
console.log(count); // ReferenceError: count is not defined
Output :Â
In this example, we can freely access the count variable within the scope of the counter() function.
However when we try to access the count variable outside the scope of counter() function then the count variable becomes inaccessible. If you try to access the count variable from outside the scope then Javascript throws an error ReferenceError: count is not defined.
This clearly shows that if you have defined a variable inside a code block or a function then you can only use that variable inside that code block or function scope. The above example clearly demonstrates this behavior.
The best thing about scope is that you can reuse the common variable names like (initial, final, current, count, index etc) in different scopes without any collisions.
Let us take the example of two functions counter() and bar() which will have their own function scopes but same named variable count.
For Example :
function counter() {
// "counter" function scope
let count = 20;
console.log(count); // logs 20
}
function bar() {
// "bar" function scope
let count = 10;
console.log(count); // logs 10
}
counter();
bar();
Output :
In this example, by seeing the output we can say that the count variable from both the functions counter() and bar() doesn’t collide with each other.
2. Scope Nesting in Javascript
Let us know play with scope and nest one scope into another. Let us take an example in which we are nesting innerFunction() inside the outerFunction().
Most people have a common question that whether they will be able to access outerVar of the outerFunction() from within the innerFunction() or not.
So let’s try to see it with the help of an example so that we can understand it better
In this example, we are able to access the value of the outerVar inside the innerFunction() scope.
By seeing this example we can conclude two things :
We can nest the scopes.
We can access the variables of the outer scope inside the inner scopes.
3. Lexical Scope in Javascript
Now after seeing the above example you would have a doubt in your mind that how it is possible to access the outerVar inside the innerFunction() as outerVar corresponds to the outerFunction().
This is all possible with the help of lexical scoping in javascript. In lexical scoping the accessibility of the variable is determined by the position of the variables inside the nested scope.
In simple words, lexical scoping means that inside the inner scope you can access the variables of the outer scope.
In the above example, the lexical scope of innerOfInnerofFunc() consists of the scope of innerFunc() and the global scope. In the innerOfInnerOfFunc, we can access all the lexical scope variables globalVar, myInnerVar and myVar.
Now the lexical scope of innerFunc() consists of the func() and the global scope. And within the innerFunc() you can access the lexical scope variables myVar and globalVar.
Finally at last now the lexical scope of the func() consists of only the global scope.And within the func() we can access the lexical scope variable globalVar.
4. Closure
As we all know lexical scope allows us to access the variable statically of the outer scopes. After that, there is just one step until the closure.
So let us again take a look at the example of outerFunc() and innerFunc().
In the above example, we all know that in the innerFunc() scope the variable outerVar is accessed from the lexical scope.
From the above example, we can note that the invocation of the innerFunc() happens inside the lexical scope (which is the scope of the outerFunc()).
So let us try to play with the invocation of the innerFunc() and now let the invocation of the innerFunc() happen outside of its lexical scope. In general, we will be doing the execution of the innerFunc() inside a function named as executive function. Can you tell whether we will be able to access the outerVar inside the innerFunc() or not?
Let us try to explain with a code snippet so that you can understand it better.
In the above example, innerFunc() is executed outside its lexical scope but in the scope of the executive function. But the innerFunc() still has access to the outerVarfrom its lexical scope. In simpler words, we can say that the innerFunc() is closure as it closes over the outerVar from its lexical scope.
In general, we can say that closure is known for capturing the variable from the lexical scope.
If you want to understand closures better then there is a rule of thumb that says that if inside a function you are able to see an alien variable (which is not defined inside the function) most likely the function is known to be closure as the alien variable is captured.
Conclusion
This was a complete explanation of how closures work in javascript. Hopefully, by reading this article I am sure you might have got a deep understanding of how closures work. The final takeaways we can take from this article are described below:
The scope is ruled by the accessibility of the variables.
In lexical scoping, the accessibility of the variable is determined by the position of the variables inside the nested scope.
And finally, a closure is a function that is known for capturing the variables from the lexical scope.