1. 全局作用域(Global Scope)
在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說以下幾種情形擁有全局作用域:
(1)最外層函數和在最外層函數外面定義的變量擁有全局作用域,例如:
var authorName="山邊小溪";
function doSomething(){
var blogName="夢想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName); //山邊小溪
alert(blogName); //腳本錯誤
doSomething(); //夢想天空
innerSay() //腳本錯誤
(2)所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:
function doSomething(){
var authorName="山邊小溪";
blogName="夢想天空";
alert(authorName);
}
doSomething(); //山邊小溪
alert(blogName); //夢想天空
alert(authorName); //腳本錯誤
(3)所有window對象的屬性擁有全局作用域
一般情況下,window對象的內置屬性都擁有全局作用域,例如window.name、window.location、window.top等等。
1. 局部作用域(Local Scope)
和全局作用域相反,局部作用域一般只在固定的代碼片段內可訪問到,最常見的例如函數內部,所有在一些地方也會看到有人把這種作用域稱為函數作用域,例如下列代碼中的blogName和函數innerSay都只擁有局部作用域。
function doSomething(){
var blogName="夢想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //腳本錯誤
innerSay(); //腳本錯誤
作用域鏈(Scope Chain)
在JavaScript中,函數也是對象,實際上,JavaScript里一切都是對象。函數對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函數被創建的作用域中對象的集合,這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。
當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。例如定義下面這樣一個函數:
function add(num1,num2) {
var sum = num1 + num2;
return sum;
在函數add創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):
函數add的作用域將會在執行時用到。例如執行如下代碼:
var total = add(5,10);
執行此函數時會創建一個稱為“運行期上下文(execution context)”的內部對象,運行期上下文定義了函數執行時的環境。每個運行期上下文都有自己的作用域鏈,用于標識符解析,當運行期上下文被創建時,而它的作用域鏈初始化為當前運行函數的[[Scope]]所包含的對象。
這些值按照它們出現在函數中的順序被復制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示: