1. 程式人生 > >javaScript作用域和作用域鏈詳解

javaScript作用域和作用域鏈詳解

作用域就是一個變數或者函式能夠訪問到區域。
ES5並沒有塊級作用域,在ES2015中已經新增塊級作用域。
例項程式碼:

var name = " 清風明月 "function mainA(){
    var name = "qingfeng";
    console.log(name);
}
mainA();  //結果:qingfeng
console.log(name); //清風明月

在上面的程式碼中,第一個name變數屬於全域性作用域,在程式碼中的任何位置都可以訪問。
第二個name屬於函式作用域,只能夠在mainA()中使用,並且區域性作用域變數可以覆蓋它上層作用域同名變數。

var name = " 清風明月 "function mainA(){
    // var name = "qingfeng";
    console.log(name);
}
mainA();  //結果:清風明月
console.log(name); //結果:清風明月

函式內部的name宣告已經被刪除,那函式是如何找到全域性作用域上的name的?
ECMAScript中有一個重要的概念:作用域鏈(scope Chain),每一個執行上下文都會關聯一個作用域鏈。

函式後面加多個()是什麼意思?
f()是執行f函式,返回子函式
f()()是執行子函式,返回孫函式
f()()()是執行孫函式

我們可以認為作用域鏈是當前執行上下文的一個屬性,它指向一個變數物件堆疊。

function mainA(){
       function mainB(){
            //code
    }
    return mainB();
}
mainA()();
mainB函式上下的作用域可以表示為如下:
Scope = [
    AO(mainB),
    AO(mainA),
    VO(global)
]

當查詢一個變數的時候,首先會在AO(mainB)中查詢,如果沒有則上溯到AO(mainA)查詢,以此類推。
更準確的說每一個function函式都有一個內部[[scope]]指標,它指向一個變數物件堆疊。
也就是說作用域鏈Scope = 當前AO + [[scope]].
強調:在作用域和作用域鏈在建立時就已經確定

變數物件VO 和 活動物件AO
變數物件VO:是與執行上下文相關的特殊物件,用來儲存上下文的函式宣告,函式形參和變數。在global全域性上下文中,變數物件也是全域性物件自身,在函式上下文中,變數物件被表示為活動物件AO。

活動變數AO:當函式被呼叫後,這個特殊的活動物件就被建立了。它包含普通引數與特殊引數物件(具有索引屬性的引數對映表)。活動物件在函式上下文中作為變數物件使用。
在函式執行上下文中,VO是不能直接訪問的,此時由活動物件(activation object,縮寫為AO)扮演VO的角色。