What are Closures?
This is probably the hardest question of all these questions because Closures is a controversial topic. So I'm gonna explain it from what I understand.
Closures is simply the ability of a function at the time of declaration to remember the references of variables and parameters on its current scope, on its parent function scope, on its parent's parent function scope until it reaches the global scope with the help of Scope Chain. Basically it is the Scope created when the function was declared.
Examples are a great way to explain closures.
//Global's Scope
var globalVar = "abc";
function a(){
//testClosures's Scope
console.log(globalVar);
}
a(); //logs "abc"
/* Scope Chain
Inside a function perspective
a's scope -> global's scope
*/
In this example, when we declare the a
function the Global Scope is part of a's
closure.
The reason for the variable globalVar
which does not have a value in the image because of the reason that the value of that variable can change based on where and when we invoke the a
function.
But in our example above the globalVar
variable will have the value of abc.
Ok, let's have a complex example.
var globalVar = "global";
var outerVar = "outer"
function outerFunc(outerParam) {
function innerFunc(innerParam) {
console.log(globalVar, outerParam, innerParam);
}
return innerFunc;
}
const x = outerFunc(outerVar);
outerVar = "outer-2";
globalVar = "guess"
x("inner");
This will print "guess outer inner". The explanation for this is that when we invoke the outerFunc
function and assigned the returned value the innerFunc
function to the variable x
, the outerParam
will have a value of outer even though we assign a new value outer-2 to the outerVar
variable because
the reassignment happened after the invocation of the outer
function and in that time when we invoke the outerFunc
function it's look up the value of outerVar
in the Scope Chain, the outerVar
will have a value of "outer". Now, when we invoke the x
variable which have a reference to the innerFunc
, theinnerParam
will have a value of inner because thats the value we pass in the invocation and the globalVar
variable will have a value of guess because before the invocation of the x
variable we assign a new value to the globalVar
and at the time of invocation x
the value of globalVar
in the_Scope Chain_ is
guess.
We have an example that demonstrates a problem of not understanding closure correctly.
const arrFuncs = [];
for(var i = 0; i < 5; i++){
arrFuncs.push(function (){
return i;
});
}
console.log(i); // i is 5
for (let i = 0; i < arrFuncs.length; i++) {
console.log(arrFuncs[i]()); // all logs "5"
}
This code is not working as we expected because of Closures.
The var
keyword makes a global variable and when we push a function
we return the global variable i
. So when we call one of those functions in that array after the loop it logs 5
because we get
the current value of i
which is 5
and we can access it because it's a global variable. Because Closures keeps the references of that variable not its values at the time of it's creation. We can solve this using IIFES or changing the var
keyword to let
for block-scoping.