javascript之作用域及作用域鏈
在看js權威指南時,感覺上面講的不太詳細,沒看懂什麼意思,就找了有關的視訊,將視訊講解記錄下來並加以整理,防止自己遺忘,以下是正文。
在介紹作用域與作用域鏈之前,先要了解執行(執行)上下文的概念,執行期上下文的定義為:當函式執行時,會建立一個稱為執行期上下文的內部物件。一個執行期上下文定義了一個函式執行時的環境,函式每次執行時對應的執行上下文都是獨一無二的,所以多次呼叫一個函式會導致建立多個執行上下文,當函式執行完畢,它所產生的執行上下文被撤銷。
[[scope]]:每個javascript函式都是一個物件,物件中有些屬性我們可以訪問,有些不可以,這些屬性僅供javascript引擎存取,[[scope]]就是其中一個,[[scope]]就是我們所說的作用域,其中儲存了執行期上下文的集合,是物件的一個隱式屬性,不能使用。
作用域鏈:[[scope]]中所儲存新的執行期上下文物件的集合,這個集合呈鏈式連結,我們把這種鏈式連結叫做作用域鏈。
查詢變數:在哪個函式中查詢變數,就在哪個函式生成的作用域鏈的頂端(第零位)依次向下查詢。
舉個例子:
function a() {
function b() {
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();
// 函式被定義時,其scope中就存了東西,存的Global Object
a定義 a[[scope]]中存0:GO{}(全域性物件)
a執行 a[[scope]]中存0:AO{}(活動物件),
1:GO{}
b被建立時,儲存了a的勞動成果(換句話說,b是站在a的肩膀上看世界),與a的作用域鏈完全一樣
b在執行時,也要生成自己的執行上下文(AO),置於作用域鏈頂端
b執行完之後,銷燬自己的執行上下文,(與自己的AO斷開聯絡,對比上圖紅線部分表示已斷開)
b執行完後,因為b()是a()的最後一條語句,因此a要銷燬自己的執行上下文,b函式也因此被銷燬,b函式(已被銷燬)與自己的作用域鏈斷開連結(從圖中可以看出b函式已經不存在)
當a()被再次執行時,就會生成全新的執行上下文,又產生一次b()的定義,又一個全新的b函式儲存了a的勞動成果 ,再次等待執行,執行時又生成一個全新的執行上下文的作用域鏈。
又一個栗子:
function a() {
function b() {
function c() {
}
c();
}
b();
}
a();
a defined a.[[scope]]-->0:GO;
a doing a.[[scope]]-->0:aAO
1:GO;
a的執行產生b的定義
b defined b.[[scope]]-->0:aAO
1:GO;
b doing b.[[scope]]-->0:bAO
1:aAO
2:GO;
b的執行產生c的定義
c defined c.[[scope]]-->0:bAO
1:aAO
2:GO;
c doing c.[[scope]]-->0:cAO
1:bAO
2:aAO
3:GO;
當c被執行完,就返回到c被定義的狀態,如果c在此狀態又執行一次,則生成一個新的cAO,與之前的cAO是不同的,但bAO,aAO,GO都是相同的,因為都是基於c的定義。
得出結論:訪問函式時,只要訪問其作用域鏈就可以,(只能從裡往外看,不能從外往裡看),所有的AO和BO都是一樣的
注:只有a執行才會導致b被定義