在上一篇裏,留下了一個例子,如果對那個例子不是太懂,沒關係,我會在這一篇裏詳細講一下我對這個例子的理解。
下面是這個例子:
function a(){
var age=21;
var height=178;
var weight=70;
function b(){
alert(age);//undefined
alert(height);//178
var age=25;
height=180; //相當於是在全局作用域裏聲明瞭height變量。
alert(age);//25
alert(height); //180
}
b();
}
a(); //備註:如果在函數作用域內聲明變量不加var,相當於是在全局作用域裏聲明瞭這個變量。
爲了更好的理解,我們變一下這個代碼,
var height;
function a(){
var age=21;
var height=178;
var weight=70;
function b(){
alert(age); //undefined
alert(height); //178
var age=25;
height=180;
alert(age); //25
alert(height); //180
}
a();
我們來一步一步的理解這個例子:
第一步,在加載程序時,已經確定了全局上下文環境,並隨着程序的執行而對變量就行賦值;
第二步,程序執行到第31行,調用a(),此時生成此次調用a()函數時的上下文環境,壓棧,並將此上下文環境設置爲活動狀態
第三步,執行到第28行時,調用b(),生成此次調用的上下文環境,壓棧,並設置爲活動狀態
(可不要忘了執行上下文的兩個階段,一個是創建階段,一個是執行階段,如果忘記了,趕緊翻一下我之前的文章喲)
到此,我們可以理解爲什麼第一個alert(age)的結果是undefined,從b()創建階段時的上下文可知,age:undefined . 爲什麼語句height=180 沒有在b()創建階段時的上下文生成height:undefined?因爲此時height=180是賦值語句,不是變量的聲明語句。只有變量的聲明語句纔會在b()創建階段時的上下文中生存相應的屬性。
爲什麼第二個alert(height)的結果是178呢?這時候就要聯繫到作用域鏈的知識了,因爲在b()的作用域所對應的執行上下文裏沒找到height的屬性,所以從創建函數b()的作用域所對應的執行上下文裏找相關屬性,也就是a()的執行上下文,在a()的執行上下文裏找到了height屬性,它的屬性值爲178.
爲什麼第三個alert(age)的結果是25呢?這個就很好理解了吧,在b()執行階段的上下文裏,會完成對變量的賦值, 所以age賦值爲25.
爲什麼第四個alert(height)的結果是180呢?因爲height=180是個賦值語句,所以它就會找到height的屬性,把它賦值爲180,沿着作用域鏈,它在a()的上下文找到了height屬性,並把它賦值爲180,覆蓋掉原來的屬性值178.
如果理解了這個例子,是不是對執行上下文,作用域鏈的理解更深刻了呢。
我們在第一篇就講到,閉包和執行上下文,作用域聯繫緊密,下一篇就來講一講在js中那個“深奧”的閉包。
下一篇: javascript執行上下文、作用域與閉包(第六篇)—閉包
如果還沒懂的趕緊看一遍我之前的文章,並且一定要看懂噢。
javascript執行上下文、作用域與閉包(第一篇)—執行上下文
javascript執行上下文、作用域與閉包(第二篇)—作用域
javascript執行上下文、作用域與閉包(第三篇)—自由變量與作用域鏈
javascript執行上下文、作用域與閉包(第四篇)—作用域與執行上下文