(O)js核心:做用域鏈

做用域

   在一個函數被調用的時候,函數的做用域纔會存在。此時,在函數尚未開始執行的時候,開始建立函數的做用域:
   函數做用域的建立步驟:
  1.函數形參的聲明。
  2.函數變量的聲明。
  3.普通變量的聲明。
  4.函數內部的this指針賦值。(PS: 在一個函數中,this老是指向當前函數的全部者對象, this 老是在運行時才能肯定其具體的指向, 也才能知道它的調用對象)javascript

  ......函數內部代碼開始執行!
   因此,在這裏也解釋了,爲何說函數被調用時,聲明提早,在建立函數做用域的時候就會先聲明各類變量html

 

 

做用域鏈(Scope Chain)

   在JavaScript中,函數也是對象,實際上,JavaScript裏一切都是對象。函數對象和其它對象同樣,擁有能夠經過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函數被建立的做用域中對象的集合,這個集合被稱爲函數的做用域鏈,它決定了哪些數據能被函數訪問。前端

   當一個函數建立後,它的做用域鏈會被建立此函數的做用域中可訪問的數據對象填充。例如定義下面這樣一個函數:java

function add(num1,num2) {
    var sum = num1 + num2;
    return sum;
}

   在函數add建立時,它的做用域鏈中會填入一個全局對象,該全局對象包含了全部全局變量,以下圖所示(注意:圖片只例舉了所有變量中的一部分):函數

   函數add的做用域將會在執行時用到。例如執行以下代碼:性能

var total = add(5,10);

   執行此函數時會建立一個稱爲「運行期上下文(execution context)」的內部對象,運行期上下文定義了函數執行時的環境。每一個運行期上下文都有本身的做用域鏈,用於標識符解析,當運行期上下文被建立時,而它的做用域鏈初始化爲當前運行函數的[[Scope]]所包含的對象。優化

   這些值按照它們出如今函數中的順序被複制到運行期上下文的做用域鏈中。它們共同組成了一個新的對象,叫「活動對象(activation object)」,該對象包含了函數的全部局部變量、命名參數、參數集合以及this,而後此對象會被推入做用域鏈的前端,當運行期上下文被銷燬,活動對象也隨之銷燬。新的做用域鏈以下圖所示:this

   在函數執行過程當中,沒遇到一個變量,都會經歷一次標識符解析過程以決定從哪裏獲取和存儲數據。該過程從做用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,若是找到了就使用這個標識符對應的變量,若是沒找到繼續搜索做用域鏈中的下一個對象,若是搜索完全部對象都未找到,則認爲該標識符未定義。函數執行過程當中,每一個標識符都要經歷這樣的搜索過程。spa

 

做用域鏈和代碼優化

   從做用域鏈的結構能夠看出,在運行期上下文的做用域鏈中,標識符所在的位置越深,讀寫速度就會越慢。如上圖所示,由於全局變量老是存在於運行期上下文做用域鏈的最末端,所以在標識符解析的時候,查找全局變量是最慢的。因此,在編寫代碼的時候應儘可能少使用全局變量,儘量使用局部變量。一個好的經驗法則是:若是一個跨做用域的對象被引用了一次以上,則先把它存儲到局部變量裏再使用。例以下面的代碼:指針

function changeColor(){
    document.getElementById("btnChange").onclick=function(){
        document.getElementById("targetCanvas").style.backgroundColor="red";
    };
}

   這個函數引用了兩次全局變量document,查找該變量必須遍歷整個做用域鏈,直到最後在全局對象中才能找到。這段代碼能夠重寫以下:

function changeColor(){
    var doc=document;
    doc.getElementById("btnChange").onclick=function(){
        doc.getElementById("targetCanvas").style.backgroundColor="red";
    };
}

   這段代碼比較簡單,重寫後不會顯示出巨大的性能提高,可是若是程序中有大量的全局變量被從反覆訪問,那麼重寫後的代碼性能會有顯著改善。

 

參考資料:http://www.cnblogs.com/renlong0602/p/4398883.html 

參考資料:http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html

相關文章
相關標籤/搜索