闭包
词法作用域是在定义时确定的: [[scope]]
上下文是函数执行时的变量环境: vo + [[scope]]
所以闭包执行的时候是通过[[scope]]来访问作用域链上的变量。
函数的从声明到执行的过程:
- 创建(引擎准备并填充三个变量)
+ vo:函数参数,内部变量, 函数内部声明
+ scope chain: 作用域链
+ 确定this的值并填充 - 执行
- 词法作用域
代码创建时定义的静态作用域 - 上下文
代码运行时,this的指向
作用域链(函数定义的时候确定):
每个函数在定义的时候都有一个[[scopes]]属性,指向的是它的作用域链。直到函数销毁。其中closure是闭包,script指向自身变量,global指向全局变量
[[Scopes]]: Scopes[3]
0: Closure (foo) {y: 20}
1: Script {bar: ƒ}
2: Global {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window,
function foo() {
alert(x);
}
(function () {
var x = 20;
foo(); // 10, but not 20
})();
var x = 10;
// 通过Function构造的函数,不能访问闭包变量,只能访问全局变量,[[scope]]作用域链没有closure
function foo() {
var y = 20;
function barFD() { // 函数声明
alert(x);
alert(y);
}
var barFE = function () { // 函数表达式
alert(x);
alert(y);
};
var barFn = Function('alert(x); alert(y);');
barFD(); // 10, 20
barFE(); // 10, 20
barFn(); // 10, "y" is not defined
}
foo();
// 变量查找= 作用域链查找(直到global没有找到) + 原型链查找
function foo() {
// var x = 20;
function bar() {
alert(x);
}
bar();
}
Object.prototype.x = 10;
foo(); // 20
```
* 在代码执行阶段有两个声明能够修改作用域链:
* with
* catch
``` javascript
// 普通的闭包的作用域链在定义的时候确定,不能修改参数的调用值
var x = 10;
function foo() {
alert(x);
}
(function () {
var x = 20;
foo(); // 10, but not 20
})();
// 使用with之后,with绑定的对象推到作用域链的最前端,同时再进行变量赋值,能够改变参数的调用值
var x = 10, y = 10;
with ({x: 20}) {
var x = 30, y = 30;
alert(x); // 30
alert(y); // 30
}
alert(x); // 10
alert(y); // 30
```
网友评论