執行環境定義了變量或函數有權訪問的其他數據,決定了它們的各自行為。每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中,雖然我們無法訪問這個對象,但是解析器在處理數據時會在後台使用它。
全局執行環境是最外圍的一個環境,在web浏覽器中,全局執行環境被認為是window對象,因此所有全局變量和函數都是作為window對象的屬性和方法創建的。
某個執行環境中的所有代碼執行完畢後,該環境被銷毀,保存在其中的所有變量和函數定義也隨之全部被銷毀。
當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈。作用域鏈的用途是保證對執行環境有權訪問的所有變量和函數的有序訪問。
作用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象。如果這個環境是函數,則將其活動對象作為變量對象。活動對象在最開始時只包含一個變量,即arguments對象(這個對象在全局環境中是不存在的)。作用域鏈的下一個變量對象來自於包含(外部)環境,在下一個變量外部環境對象則來自下一個包含環境,這樣一直延續到全局執行環境,全局執行環境的對象始終都是作用域鏈中的最後一個對象。
示例1:
var color = "blue";
function changeColor(){
if (color === "blue"){
color = "red";
} else {
color = "blue";
}
}
changeColor();
alert("Color is now " + color);//Color is now red
解析:函數changeColor()的作用域包含兩個對象,它自己的變量對象(其中定義著arguments對象)和全局環境的變量對象(color)。
示例2:
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//color, anotherColor, and tempColor are all accessible here
}
//color and anotherColor are accessible here, but not tempColor
swapColors();
}
changeColor();
//anotherColor and tempColor aren't accessible here, but color is
alert("Color is now " + color);
解析:上面一共有3個執行環境:全局環境,changeColor()的局部環境和swapColors()的局部環境。
全局環境中有一個變量color和一個函數changeColor()。
changeColor()的局部環境中有一個名為anotherColor的變量和一個名為swapColor()的函數,也可以訪問全局環境中的變量color。
swapColor()的局部環境中有一個變量tempColor,該變量只能在這個環境中訪問到,同時還能訪問前面兩個執行環境中的所有變量。
下面的圖片就展示了上面例子的作用域鏈:
JavaScript中沒有塊級作用域
在其它語言中,由花括號封閉的代碼塊都有自己的作用域,但是在JavaScript中卻不是這樣的。
示例3:
if(true){
var color="blue";
}
alert(color);//"blue"
當上面代碼執行完了,變量color並沒有被銷毀,而是一直存在於全局環境中了。
for(var i=0;i<10;i++){
doSomething(i);
}
alert(i);//10
對於有塊級作用域的語言來說,for語句初始化變量的表達式所定義的變量,只會存在於循環的環境之中。而對於JavaScript來說,由for語句創建的變量i即使在for循環結束後,也依舊會存在於循環外部的執行環境中。
變量申明
在JavaScript中,使用var申明的變量會自動添加到最接近的環境中。在函數內部,最接近的環境就是函數的局部環境。
如果在申明變量省略var這個關鍵字,即使在函數運行完了,在外部也能夠訪問到這個變量,就好像變成全局變量是的。
示例4:
使用var申明的
function add(num1, num2) {
var sum = num1 + num2;
return sum;
}
var result = add(10, 20); //30
alert(sum); //causes an error since sum is not a valid variable
沒有使用var申明的
function add(num1, num2) {
sum = num1 + num2;
return sum;
}
var result = add(10, 20); //30
alert(sum); //30