闭包理解 - ythy/blog GitHub Wiki
A closure is the combination of a function and the lexical environment within which that function was declared.
Lexical Environments
I think it is helpful to think about why this is important. In short, one has to wonder, how does the machine know where to look for all the variables declared in the code? The LexicalEnvironment is where this "identifier resolution" happens!
The official ES5 docs defines Lexical Environment (an abstract concept really) as the place where “the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code” is stored. Jargon aside, there are two main takeaways from this definition:
- Identifier associations are simply the binding between variable and function declarations with their values. (e.g., let x = 10, 'x' is bound to '10').
- Lexical structure is just describing the actual location where the code was written. See below.
let foo = function (a) {
let b = 10; // 'b' and 'bar' is in the lexical structure of 'foo'
let bar = function(a) {
let c = 20; // however, 'c' would only be in the lexical
return a + b + c; // structure of 'bar' because 'c' is written
}; // inside the 'bar' function.
};
This about where the code is written and that’s how you know which variable and function declarations go into which LexicalEnvironment.
Now, within this Lexical Environment are two components: (1) the environment record and (2) a reference to the outer environment.
- The environment record is the place where the variable and function declarations are stored.
- The reference to the outer environment is the way in which the machine conducts identifier resolution (scope).
- In the global code environment, you can expect the built-in Object/Array/etc. prototype functions inside this environment record as well as any user-defined global variables. And the reference to the outer environment would be set to null (as it is the outermost environment).
- In function code, the user-defined variables inside the function AND the lexical structure (see above!) are stored in the environment record. And the reference to the outer environment can be the global environment, or whatever outer function that wraps around the inner function.
conclusion
- As implied above, for global code, the LexicalEnvironment is set to the Global Environment (with the object environment record and the reference to the outer environment set to null).
- For function code, the LexicalEnvironment will contain all the variable and function declarations. This is actually where we see the "hoisting" phenomenon -- where declarations are brought to the top of its lexical scope prior to any assignment to a value.
examples
- 形成闭包 3个函数访问的i都在一个 globle 环境
let array = [];
for (var i = 0, max = 3; i < max ; i ++) {
array.push(()=>{
console.log(i);
});
}
array[0](); //3
- 形成闭包 但是 j 的声明不在globle环境下, 所以没有共享。
let array = [];
for (var i = 0, max = 3; i < max ; i ++) {
let j = i;
array.push(()=>{
console.log(j);
});
}
array[0](); //0
- 形成闭包 j在单独环境下 不共享
function call(j){
return ()=>{
console.log(j);
}
}
let array = [];
for (var i = 0, max = 3; i < max ; i ++) {
array.push(call(i));
}
array[0]();