1. 程式人生 > >javascript之作用域及作用域鏈

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被定義