作用域
作用域就是變量和函數的可訪問範圍,控制着變量和函數的可見性與生命週期,JavaScript中只有全局作用域與局部作用域
如何判斷是全局還是局部作用域?
全局:
- 最外層函數和在最外層函數外面定義的變量擁有全局作用域
- 所有末定義直接賦值的變量自動聲明爲擁有全局作用域
- 所有window對象的屬性擁有全局作用域
局部:
- 函數內部用var聲明的變量
var a=3; //全局變量
function fn(b){ //局部變量
c=2; //全局變量
var d=5; //局部變量
function subFn(){
var e=d; //父函數的局部變量對子函數可見
for(var i=0;i<3;i++){
console.write(i);
}
alert(i);//3, 在for循環內聲明,循環外function內仍然可見,沒有塊作用域
}
}
alert(c); //在function內聲明但不帶var修飾,仍然是全局變量
作用域與執行上下文是完全不同的兩個概念。
JavaScript代碼的整個執行過程,分爲兩個階段,代碼編譯階段與代碼執行階段。編譯階段由編譯器完成,將代碼翻譯成可執行代碼,這個階段作用域規則會確定。執行階段由引擎完成,主要任務是執行可執行代碼,執行上下文在這個階段創建。
作用域鏈
分析執行上下文的生命週期
我們知道函數在調用激活時,會開始創建對應的執行上下文,在執行上下文生成的過程中,變量對象,作用域鏈,以及this的值會分別被確定。
作用域鏈,是由當前環境與上層環境的一系列變量對象組成,它保證了當前執行環境對符合訪問權限的變量和函數的有序訪問。
爲了幫助大家理解作用域鏈,我我們先結合一個例子來說明。
var a = 20;
function test() {
var b = a + 10;
function innerTest() {
var c = 10;
return b + c;
}
return innerTest();
}
test();
在上面的例子中,全局,函數test,函數innerTest的執行上下文先後創建。我們設定他們的變量對象分別爲VO(global),VO(test), VO(innerTest)。而innerTest的作用域鏈,則同時包含了這三個變量對象,所以innerTest的執行上下文可如下表示。
innerTestEC = {
VO: {...}, // 變量對象
scopeChain: [VO(innerTest), VO(test), VO(global)], // 作用域鏈
}
我們可以直接用一個數組來表示作用域鏈,數組的第一項scopeChain[0]爲作用域鏈的最前端,而數組的最後一項,爲作用域鏈的最末端,所有的最末端都爲全局變量對象。