閉包
詞法作用域是在定義時(shí)確定的: [[scope]]
上下文是函數(shù)執(zhí)行時(shí)的變量環(huán)境: vo + [[scope]]
所以閉包執(zhí)行的時(shí)候是通過[[scope]]來訪問作用域鏈上的變量。
函數(shù)的從聲明到執(zhí)行的過程:
- 創(chuàng)建(引擎準(zhǔn)備并填充三個(gè)變量)
+ vo:函數(shù)參數(shù),內(nèi)部變量, 函數(shù)內(nèi)部聲明
+ scope chain: 作用域鏈
+ 確定this的值并填充 - 執(zhí)行
- 詞法作用域
代碼創(chuàng)建時(shí)定義的靜態(tài)作用域 - 上下文
代碼運(yùn)行時(shí),this的指向
作用域鏈(函數(shù)定義的時(shí)候確定):
每個(gè)函數(shù)在定義的時(shí)候都有一個(gè)[[scopes]]屬性,指向的是它的作用域鏈。直到函數(shù)銷毀。其中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構(gòu)造的函數(shù),不能訪問閉包變量,只能訪問全局變量,[[scope]]作用域鏈沒有closure
function foo() {
var y = 20;
function barFD() { // 函數(shù)聲明
alert(x);
alert(y);
}
var barFE = function () { // 函數(shù)表達(dá)式
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
```
* 在代碼執(zhí)行階段有兩個(gè)聲明能夠修改作用域鏈:
* with
* catch
``` javascript
// 普通的閉包的作用域鏈在定義的時(shí)候確定,不能修改參數(shù)的調(diào)用值
var x = 10;
function foo() {
alert(x);
}
(function () {
var x = 20;
foo(); // 10, but not 20
})();
// 使用with之后,with綁定的對(duì)象推到作用域鏈的最前端,同時(shí)再進(jìn)行變量賦值,能夠改變參數(shù)的調(diào)用值
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
```