ECMAScript作用域與作用域鏈
執行環境(execution context,我們也叫做“環境”)是定義變量和函數有權訪問的其他數據的重要概念,在JavaScript中它決定了各自的行為,在每個執行環境中與之關聯的變量對象(vanriable object),環境中定義的所有變量和函數都保存在這個變量中,解析器會在後臺處理數據是使用這個對象。
一、變量的聲明
我們可以聲明全局變量和局部變量,直接使用var聲明一個變量,該變量會自動被添加到最近的環境中:
function sum(a1, a2) {
var enter = a1 + a2;
return enter;
}
var result = sum(20,30);//50
console.log(enter);//報錯
如果初始化變量式沒有使用var聲明,該變量會自動被添加到全局環境:
function sum(a1, a2) {
all = a1 + a2;
return all;
}
var result = sum(20,30);//50
console.log(all);//50
註意:在嚴格模式下,初始化未經聲明的變量會導致錯誤。
二、變量作用域
打開Google Chrome瀏覽器開發工具Developer Tools,快捷鍵(ctrl + shift + J):
var global = "window";
function area() {
var enter = "thisArea";//局部變量在函數執行結束時會被銷毀
console.log("輸出" + global);//訪問全局變量global
}
area();
console.log(enter);//輸出錯誤
在全局執行環境是最外圍的一個執行環境,在web瀏覽器中,全局執行環境被認為是window對象,所以說,全局變量和函數都時作為window對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢會被銷毀,其中保存的變量和參數定義也隨之銷毀。
三、作用域鏈
當你要執行一段代碼時,會創建變量對象的一個作用域鏈(scope chain),作用域鏈可以保證對執行環境有權訪問的所有變量和函數的有序訪問。在作用域鏈前端,始終都是當前執行的代碼所在環境的變量對象。而如果時環境是函數,則將其活動對象作為變量對象,這個活動對象開始時只包含一個變量,即arguments對象。對每個包含環境往上搜索,一直到全局執行環境,它作為最後一個對象。
標識符解析式沿著作用域鏈遞進往上搜索,搜索過程開始在作用域鏈前端開始,一直追溯到全局環境的變量對象,如果在全局環境沒有找打這個標識符,則這會被認為該變量未聲明,而會導致輸出錯誤:
var temper = 38;
function changTemper() {
if (temper > 37){
console.log("Your temperature is too high.");
}else if(temper = 37) {
console.log("Your body temperature is normal.");
}else{
console.log("Your body temperature is too low.");
}
}
changTemper();//Your temperature is too high.
函數內部可以訪問外部環境的變量,它們是通過作用域鏈來查找該變量的,如果途中找到該變量,就會停止終止查找。
還有就是,局部作用域中定義的變量可以在外部環境中域全局變量互換使用。
var global = 1;
function area1() {
var thisOne = 2;
function area2() {
var thisTwo = thisOne;
thisOne = global;
global = thisTwo;
var thisTwo = arae;//報錯
/*
能訪問到的說明外部有,或者本函數有這個變量。
thisTwo需要訪問外部變量的時候它會一級一級往上搜索
如果沒有搜索到,就會報錯。
*/
}
area2();
}
area1();
四、延長作用域鏈
執行環境的類型總共有兩種——全局和局部函數,但還是有其他辦法來延長作用域鏈。有一些語句能夠前作用域鏈前端臨時增加一個變量對象,該變量對象會在代碼執行後被移除,具體來說,就是當執行流進入下列任何語句式,作用域鏈就會得到加長:
with語句
這個語句將會指定的對象添加到作用域鏈中。with語句可以接收location對象,在location對象中包含了所有的屬性和方法,這個變量對象被添加到了作用域鏈的前端。當在with語句中引用變量href式,可以在執行環境中找到。在with語句內部,定義了一個名為url的變量,因而url就成了函數執行環境的一部分。
function create() {
var de = "?debug=true";
with(location){
var url = href + de;
}
return url;//
}
總結:
- 執行環境決定了變量的生命周期;
- 執行環境有全局執行環境和函數執行環境之分;
- 每次進入一個新執行環境,都會創建一個用於搜索變量和函數的作用域鏈;
- 函數的局部環境有權訪問函數的作用域中的變量,還可以有權訪問其包含(父)環境;
- 全局環境只能訪問在全局環境中定義的變量,不能直接訪問局部環境中的任何數據;
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果您喜歡或者有所啟發,歡迎添加收藏,一起加油學習啊。
ECMAScript作用域與作用域鏈