var func = [];
const funcLength = 3;
(function(){
for(var i=0;i<funcLength;i++){
func[i] = function(){ // let me save functions, I want to reuse them in future
console.log(i);
}
}
})();
func[0](); // I want 0, why give me 3
func[1](); // I want 1, why give me 3
func[2](); // I want 2, why give me 3
Jounior developers may had been facing a problem that
"I want to generate a group of functions, each of them needs to access generated data, and encapsulation is also be considered".
Using and modifying the upper code could be the most choice. However, it does not work as expected.
Javascript Scope Chain
javascript
   
26 March 2017
   
Jerry Guan
Classic Code
Scope Chain
var x = 10;
function foo(){
var x = 200;
function bar(){
var x = 3000;
console.log(x);
}
bar();
}
foo(); // output 3000
var x = 10;
function foo(){
var x = 200;
function bar(){
// var x = 3000;
console.log(x);
}
bar();
}
foo(); // output 200
var x = 10;
function foo(){
// var x = 200;
function bar(){
// var x = 3000;
console.log(x);
}
bar();
}
foo(); // output 10
variable x are commented out.
When these pieces of code have executed at bar();, we know the execution context would look as follow.
bar(), there is a thing called scope,
and scope allows bar() to access its outer function's variables.
The left-hand side of the code, x is defined inside bar(), so the output is 3000.
Function bar() of the middle code does not contain x.
Then bar() traversal its outer function to retrieve x, x is 200.
Same thing happens on the right-hand side of the code. bar() can not find x in foo(),
but via scope, bar() still can get x equal to 10, which x is defined in global.
"use strict";
var x = 10;
function foo(){
var x = 200;
bar();
}
function bar(){
console.log(x);
}
foo(); // output 10, not 200;
bar() is defined in global, so when bar() uses scope chain to get x,
bar() outter "function", global variable x will be accessed.
Closure
If you want private variables, closure is what you want. But, is it related to Scope Chain? YES, it is. Back to our first classic example mention at the top.A closure is a function having access to the parent scope, even after the parent function has closed.
var func = [];
const funcLength = 3;
(function(){
for(var i=0;i<funcLength;i++){
func[i] = function(){ // let me save functions, I want to reuse them in future
console.log(i);
}
}
})();
After (function(){...})() run. variable i can not be directelly accessed from global.
We know that func[i] = function(){...} is defined inside the closure,
so console.log(i); can access its outter function's i via Scope Chain.
After (function(){...})() execuded, i become 3.
Then all three func[]() called will give back 3 because accessing i by traversal Scope Chain.
To get what we want, we can modify the code to
"use strict";
var func = [];
const funcLength = 3;
(function(){
for(var i=0;i<funcLength;i++){
func[i] = (function(i){
return function(){
console.log(i);
}
})(i);
}
})();
func[0](); // 0
func[1](); // 1
func[2](); // 2
"use strict";
var func = [];
const funcLength = 3;
(function(){
for(let i=0;i<funcLength;i++){
func[i] = function(){
console.log(i);
}
}
})();
func[0](); // 0
func[1](); // 1
func[2](); // 2
function(){console.log(i);} and make i as parameter.
Each time func[](); is called, it will find i in outter function's variable object, not form the for loop.
and there are different outter function's variable object. Then func[](); outputs are different.
On the right-hand side, I change
var i to let i of the for loop.
Keyword let defines a variable in block scope.
Hence, keywordIn loops, you get a fresh binding for each iteration if you let-declare a variable. The loops that allow you to do so are: for, for-in and for-of. In contrast, a var declaration leads to a single binding for the whole loop
let also works as expected.