Function along with its lexical scope is known as a closure.
Lexical scope is the ability of a function scope to access variables from the parent scope. We call the child function to be lexically bound by that of the parent function.
function x() {
let a = 10;
function y() {
console.log(a); // 10
}
y();
}
x();
Why, is the function y()
is consoling the value of a
? even though y()
does not have any variable named a
. So, the child function doesn't have any variable, it will look for it in the parent function. This way, all child functions can have access to variables or functions from the parent environment(lexical scope)
This way, y()
is enclosed with the function x()
. This is known as Closure.
The common mistake we make with the closure is understanding the memory allocation to variables. Javascript doesn't wait for anyone. It continuously just starts the execution of each line one by one.
function x() {
for(var i = 1 ; i <= 5; i++) {
setTimeout(()=> {
console.log(i)
}, i * 1000)
}
}
x();
/* output---
6
6
6
6
6
*/
What should be the answer to this? you might expect that this for loop will print 1, 2, 3, 4, and 5 after the timer completes. But, eventually, it will print 6 for all loops.
This is because the environment (or context/scope) is the same for all five setTimeout functions within the x()
function. when the first loop starts, var i
is allocated in the memory and whenever the second loop starts, it will use the reference(not value) of the i
variable. This is because the var
shares the same lexical scope.
So, the right way to do this is let
variable. The let
variable is block scope, so whenever the for loop tries to access the i
variable, because of the block scoping, every time new i
variable will be created for each loop.
function x() {
for(let i = 1 ; i <= 5; i++) {
setTimeout(()=> {
console.log(i)
}, i * 1000)
}
}
x();
/* output---
1
2
3
4
5
*/
But what if we want to set the closure of for loop with only var
variable and not let
variable?
Look carefully here, when we are doing the same thing with var
variable, the i
shares the same scope and this is making a problem for us. let's just change the scope of this i
variable.
function x() {
for(var i = 1 ; i <= 5; i++) {
function close(c) {
setTimeout(()=> {
console.log(c)
}, c * 1000)
}
close(i)
}
}
x();
/* output---
1
2
3
4
5
*/
So, here using closure, we just made a new copy of the var i
. Whenever the setTimeout function will be run for each loop, a new reference i
will be created. So, it will use the newly created variable.