首頁  >  文章  >  web前端  >  JavaScript中的作用域鍊與閉包

JavaScript中的作用域鍊與閉包

高洛峰
高洛峰原創
2016-11-26 13:11:001023瀏覽

 • 作用域
o 全域作用域
o 局部作用域
• 作用域鏈
• 執行情境
• 活動對象
• 閉包。何為閉包?從表面理解即封閉的包,與作用域有關。所以,說閉包以前先說說作用域。
作用域(scope)
        通常來說一段程式碼中使用的變數和函數並不總是可用的,限定其可用性的範圍即作用域,作用域的使用提高了程式邏輯的局部性,增強程式的可靠性,減少名字衝突。
        全域作用域(Global Scope)
        在程式碼中任何地方都能存取的對象擁有全域作用域,下列幾種情形擁有全域作用域:   變數擁有全域作用域,例如:
[javascript]
1. var outSide="var outside"; 
2. function outFunction(){ 
3.     var name="var inside"; 
3.    
5.         alert(name); 
6.     } 
7.     inSideFunction(   
11. outFunction( ); //正確  
12. inSideFunction() //錯誤 
 
2、未定義直接賦值的變數自動宣告為擁有全域作用域,例如:
[javascript] view plaincopyprint?
1. blogName="CSDNjavascript] view plaincopyprint?
1. blogName="CSDNjava " 
 3、所有window物件的屬性擁有全域作用域,例如:window物件的內建屬性都擁有全域作用域,例如window.name、window.location、window.top等
局部作用域(Local Scope)
[ javascript] 
1. function outFunction(){ 
2.                          alert(name);
5.          } 
6.          inFunction(); 
7. } 鏈結(scope chain)
         JavaScript中,JavaScript裡一切都是對象,包括函數。函數物件和其它物件一樣,擁有可以透過程式碼存取的屬性和一系列僅供JavaScript引擎存取的內部屬性。其中一個內部屬性是作用域,包含了函數被建立的作用域中物件的集合,稱為函數的作用域鏈,它決定了哪些資料能被函數存取。
  當一個函數建立後,它的作用域鏈會被建立此函數的作用域中可存取的資料物件填入。例如函數:
[javascript] 
1. function add(num1,num2) { 
2.     var sum = num1 + num2; 
}3.   add創建時,它的作用域鏈中會填入一個全域對象,該全域對象包含了所有全域變量,如下圖所示(注意:圖片只例舉了全部變量中的一部分):



        由此可見,函數的作用域鍊是創建函數的時候所創造的。
執行情境(Execute context )
        函數add的作用域會在執行時使用到,例如:
[javascript]
1. var total = add(5,10); 🠎會建立一個Execute context (執行上下文),執行上下文中就包含了add 函數運行期間所需的所有資訊。 Execute context 也有自己的 Scope chain, 當函數運行時, JavaScript 引擎會先從用 add 函數的作用域鏈來初始化執行上下文的作用域鏈。
活動物件(Active Object)
        然後JavaScript 引擎又會創建一個Active Object, 這些值按照它們出現在函數中的順序被複製到運行期上下文的作用域鏈中,它們共同組成了一個新的對象—— “活動物件(activation object)”,這個物件裡麵包含了函數運行期的所有局部變量,參數以及this 等變量,此物件會被推入作用域鏈的前端,當運行期上下文被銷毀,活動物件也隨之銷毀。新的作用域鏈如下圖所示:

JavaScript中的作用域鍊與閉包        執行上下文是動態的概念,當函數運作的時候創建,活動物件Active Object 也是一個動態的概念,它是被執行情境的作用域鏈引用的,可以得出結論:執行上下文和活動物件都是動態概念,並且執行上下文的作用域鍊是由函數作用域鏈初始化的。

        在函數執行過程中,每遇到一個變量,都會檢索從哪裡獲取和存儲數據,該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,如果找到了就使用這個標識符對應的變量,如果沒有則繼續搜尋作用域鏈中的下一個對象,如果搜尋完所有對像都未找到,則認為該標識符未定義,函數執行過程中,每個標識符都要經歷這樣的搜尋過程。

閉包(closure)
         ,一個實例,javascript代碼:
[javascript] 
1.      
         前台程式碼:
[html] 
1. 

 
2. cn/"> 3.  4. 5.  
         運作結果:無論點選那個anchor,總是會彈出anchor4,而我們根本沒有anchor4:



        當我們載入頁面時,javascript中的newLoad函數已經運作完畢,由其中的循環可知,anchor已經賦值為4。但是由先前的程式設計經驗來看,局部變數使用完畢就會銷毀,但是anchor卻沒有,顯然這裡 JavaScript 採用了另外的方式。
        閉包在 JavaScript 其實就是一個函數,並且在函數運作期間建立的,當上面的 函數被執行的時候,會建立一個閉包,而這個閉包會引用newLoad 作用域中的anchor。下面就來看看JavaScript 是如何來實現閉包的:當執行newLoad 函數的時候, JavaScript 引擎會建立newLoad函數執行上下文的作用域鏈,這個作用域鏈包含了newLoad執行時的活動對象,同時JavaScript 引擎也會建立一個閉包,而閉包的作用域鏈也會引用newload的活動對象,這樣當newload執行完的時候,雖然其執行上下文和活動對像都已經釋放了anchor,但是閉包還是引用著newload的活動對象,所以點選顯示的是「you clicked anchor4」。運作期間如圖:

JavaScript中的作用域鍊與閉包

閉包最佳化
            既然閉包出現了我們不想看到的結果,我們需要最佳化它。最佳化後的javascript(其他不變):
[javascript] 
1. 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn