As per MDN, “a closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).”
To simplify, inner functions always have access to the outer functions via closure. One important thing to note here is the lexical environment. Because of the lexical environment, the inner function has access to all the variables of its parent function.
In the below image, the yellow rectangle is the lexical environment of the parent function, and all functions contain the lexical environment of their parent function along with its local variables. The chain of the lexical environment is the scope chain.
Let’s look at the below image, here we have three functions one inside another. The innermost function child() have access to all the variables of the grandparent() because of closure.
Functions even after being returned remember their scope because of closure.
Use cases of closure
Currying
Encapsulation
Functions like memoize and once
setTimeouts
Module design pattern
Common interview questions on closure
What will the output of this code
function a() { for (var i = 0; i <= 5; i++) { setTimeout(function () { console.log(i) }, i * 1000)}}a()
The output here is 6 times 6. Due to closure the function always remembers the variables being declared during the function birth, hence i is always referencing to the same memory location(because i is declared using var) we get the final value 6 as the output every time.
Let’s make a small change, replace var with let
function a() {
for (let i = 0; i <= 5; i++) {
setTimeout(function () {
console.log(i) }, i * 1000)
}}
a()
Check out the two images and you can clearly see the difference between what I meant when I said let is a block scope.
We can resolve the above issue by simply using let instead of var. let is a block scope and every time function is called it is creating a new variable hence referencing to a different memory location.
As explained in this article It is always recommended to use either let or const because both are block-scoped.
We can solve the above without using let also. The solution is we have to refer to a different memory location, we can do this by wrapping the setTimeout within a different function. Now every time function b() is called a new copy of j is created.
function a() {
for (var i = 0; i <= 5; i++) {
function b(j) {
setTimeout(function () {
console.log(j) }, j * 1000)
}
b(i)
}}
a()
Remember closure is just an internal property of function, we can't access it explicitly. If you want to see the scopes of any function try this code.
function outer(){
let count = 0;
return function inner(){
count ++;
console.log(count)
}
}
const func = outer()
func()
func()
func()
console.dir(func)
We can see [[Scopes]] contains closure. [[]] here means the property can’t be accessed externally and is an internal JS property.
Conclusion
I hope after reading this article closure concept is clear, and you will be able to explain it better in an interview.
In case I have missed something or you have some advice or suggestions do let me know in the comment section.