<1>變量作用域
在JavaScript中全局變量的作用域比較簡單,它的作用域是全局的,在代碼的任何地方都是有定義的。然而函數(shù)的參數(shù)和局部變量只在函數(shù)體內(nèi)有定義。另外局部變量的優(yōu)先級要高于同名的全局變量,也就是說當局部變量與全局變量重名時,局部變量會覆蓋全局變量(如下面例子)。
var num = 1; //聲明一個全局變量
function func() {
var num = 2; //聲明一個局部變量
return num;
}
console.log(func()); //輸出:2
注:聲明局部變量時一定要使用var,否則,解釋器會將該變量當做全局對象window的屬性。
<2>函數(shù)作用域
在JavaScript中變量的作用域,并非和C、Java等編程語言似得,在變量聲明的代碼段之外是不可見的,我們通常稱為塊級作用域,然而在JavaScript中使用的是函數(shù)作用域(變量在聲明它們的函數(shù)體以及這個函數(shù)體嵌套的任意函數(shù)體都是有定義的)。(如下面的例子)
function func() {
console.log(num); //輸出:undefined,而非報錯,因為變量num在整個函數(shù)體內(nèi)都是有定義的
var num = 1; //聲明num 在整個函數(shù)體func內(nèi)都有定義
console.log(num); //輸出:1
}
func();
注:JavaScript的函數(shù)作用域是指在在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的,也就是說在函數(shù)體內(nèi)變量聲明之前就已經(jīng)可用了。
作為屬性的變量
當聲明一個全局變量的時候,實際上是定義了全局對象window的一個屬性。
var num = 1; //聲明全變量num
alert(window.num) //輸出:1 聲明的全局變量實際上就是聲明了一個window對象的屬性
<3>作用域鏈
在JavaScript中,函數(shù)也是對象,實際上,JavaScript里一切都是對象。函數(shù)對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內(nèi)部屬性。其中一個內(nèi)部屬性是[[Scope]],該內(nèi)部屬性包含了函數(shù)被創(chuàng)建的作用域中對象的集合,這個集合被稱為函數(shù)的作用域鏈,它決定了哪些數(shù)據(jù)能被函數(shù)訪問。
當一個函數(shù)創(chuàng)建后,它實際上保存一個作用域鏈,并且作用域鏈會被創(chuàng)建此函數(shù)的作用域中可訪問的數(shù)據(jù)對象填充。例如定義下面這樣一個函數(shù):
function func() {
var num = 1;
alert(num);
}
func();
在函數(shù)func創(chuàng)建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):
函數(shù)add的作用域?qū)趫?zhí)行時用到。例如執(zhí)行如下代碼:
執(zhí)行此函數(shù)時會創(chuàng)建一個稱為“運行期上下文(execution context)”(有人稱為運行環(huán)境)的內(nèi)部對象,運行期上下文定義了函數(shù)執(zhí)行時的環(huán)境。每個運行期上下文都有自己的作用域鏈,用于標識符解析,當運行期上下文被創(chuàng)建時,而它的作用域鏈初始化為當前運行函數(shù)的[[Scope]]所包含的對象。
這些值按照它們出現(xiàn)在函數(shù)中的順序被復(fù)制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數(shù)的所有局部變量、命名參數(shù)、參數(shù)集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示: