While researching about scope and closure, I came across this challenge from javascrip.info, The question is shown below:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function() { // create a shooter function,
alert( i ); // that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
return shooters;
}
let army = makeArmy();
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
So, what is really happening?
As we can see, each iteration of the while
loop we initialized and assigned the shooter
function and then store them in the shooters
array. Each instance has the reference to the i
variable.
Let's dive in the action of function.
When we invoke army[0]()
, it firstly search the i
variable in its local memory (which is the function's inner scope). When it cannot find i
in its local scope, it continues to populate to the outside scope and searching for i
, the current scope is now in the while
loop (inner the {...}
). In this scope there's still not any i
. It continues to search in the broader scope, which is the makeArmy
's environment, now there's one i
holding the value of 10
, and yet the 10
is logged in the alert(i)
function.
How to make the i
unique value as we wanted?
Simply we will create a copied local variable of i
in the iteration scope (while
loop's scope)
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let j = i; 👈
let shooter = function() {
alert( j ); 👈
};
shooters.push(shooter);
i++;
}
return shooters;
}
The j
is now living in the iteration scope and each iteration it holds a new value of i
incremented. And each instance of shooter
has its own unique j
but not using the outer i
j
is encapsulated in each instance of shooter
.
Conclusion:
- Be careful when using the shared variable between instances of function.
- Each block scope has it own scope
{
let scopedContent = 'Hello scope'
}
console.log(scopedContent)
// ReferenceError: scopedContent is not defined
Top comments (0)