深入理解javascript原型和閉包(13)-【範圍】和【上下文環境】,深入理解javascript

來源:互聯網
上載者:User

深入理解javascript原型和閉包(13)-【範圍】和【上下文環境】,深入理解javascript

上文簡單介紹了範圍,本文把範圍和上下文環境結合起來說一下,會理解的更深一些。

如,我們在上文中已經介紹了,除了全域範圍之外,每個函數都會建立自己的範圍,範圍在函數定義時就已經確定了。而不是在函數調用時確定。

下面我們將按照程式執行的順序,一步一步把各個上下文環境加上。另外,對上下文環境不瞭解的朋友,可以去看看之前的兩篇文章:

http://www.cnblogs.com/wangfupeng1988/p/3986420.html

http://www.cnblogs.com/wangfupeng1988/p/3987563.html

 

第一步,在載入程式時,已經確定了全域上下文環境,並隨著程式的執行而對變數就行賦值。

 

第二步,程式執行到第27行,調用fn(10),此時產生此次調用fn函數時的上下文環境,壓棧,並將此上下文環境設定為活動狀態。

 

第三步,執行到第23行時,調用bar(100),產生此次調用的上下文環境,壓棧,並設定為活動狀態。

 

第四步,執行完第23行,bar(100)調用完成。則bar(100)上下文環境被銷毀。接著執行第24行,調用bar(200),則又產生bar(200)的上下文環境,壓棧,設定為活動狀態。

 

第五步,執行完第24行,則bar(200)調用結束,其上下文環境被銷毀。此時會回到fn(10)上下文環境,變為活動狀態。

 

第六步,執行完第27行代碼,fn(10)執行完成之後,fn(10)上下文環境被銷毀,全域上下文環境又回到活動狀態。

 

結束了。像老太太的裹腳布——又臭又長!

 

最後我們可以把以上這幾個圖片串連起來看看。

串連起來看,還是挺有意思的。範圍只是一個“地盤”,一個抽象的概念,其中沒有變數。要通過範圍對應的執行內容環境來擷取變數的值。同一個範圍下,不同的調用會產生不同的執行內容環境,繼而產生不同的變數的值。所以,範圍中變數的值是在執行過程中產生的確定的,而範圍卻是在函數建立時就確定了。

所以,如果要尋找一個範圍下某個變數的值,就需要找到這個範圍對應的執行內容環境,再在其中尋找變數的值。

 

雖然本文很長,但是文字較少,圖片居多,圖片都有形象的展示,大家花十幾分鐘也能慢慢看完。但是,這節內容真的很重要。

以上代碼中,咱們還沒有設計到跨範圍取值的情況,即——自由變數。詳細內容且聽下回分解。

---------------------------------------------------------------------------

本文已更新到《深入理解javascript原型和閉包系列》的目錄,更多內容可參見《深入理解javascript原型和閉包系列》。

另外,歡迎關注我的微博。

也歡迎關注我的其他教程——別怕,都是免費的!

《微軟petshop4.0源碼解讀視頻》《json2.js源碼解讀視頻》

--------------------------------------------------------------------------


我要深入的學習javascript運行機制的東西,比如閉包,原型鏈,範圍等,有什書推薦?

上面兩個權威指南和進階程式設計都可以看。

我推薦你周愛民寫的javascript語言精髓
 
JavaScript 閉包

閉包(closure)是 ECMAScript 的文法特性,即在函數內部定義函數,內部的函數可訪問其外部函數的範圍,JavaScript 也實現了這種特性。閉包這個術語確實晦澀,但實現閉包其實很簡單,只要弄懂了 JS 的範圍規則,自然就好理解閉包了。舉個例子,
function outer(name){ // 外部的函數 var msg="hello"; function inner(){ // 內建函式 alert(msg+" "+name); } return inner(); // 返回內建函式}var clos=outer("Wang");clos();這段代碼就使用了閉包,執行代碼將彈出警告“hello Wang”。
先解釋一下範圍(scope)。在運行函數都會建立屬於函數的上下文環境(context)及範圍,範圍即當前環境範圍內的變數。JS 中最外圍的環境為 window 對象,也就是全域範圍所在的環境。當執行到下一級環境時,下一級環境會主動包含上一級的範圍,最終形成一級一級關聯的範圍鏈(對象的 [[Scope]] 屬性指向該範圍鏈)。當有下一級環境產生時,上一級環境會失活,但不會自動銷毀而儲存在一種“棧”式結構中,這樣可以保證範圍鏈的延續性,也可以環境回退時再次啟用。當前環境可訪問當前範圍鏈中的全部變數,比如上面代碼中的 inner() 函數可訪問 outer() 函數中的 msg 和 name 變數。閉包就是藉助這種範圍鏈,一方面可使內建函式可訪問外部函數的變數;另一方面,閉包還可以抑制外部函數環境的銷毀,使其變數始終儲存在記憶體中,直至不需要時再銷毀。至於閉包的應用,實際上都是一些小技巧,下面寫一些例子。
迴圈綁定事件,使迴圈過程中的索引值 i 均有效
var elems=document.getElementsByTagName('li');for(var i=0;i<elems.length;i++){ elems[i].onclick=function(i){ return (function(){ // 閉包 alert(i); }) }(i); // 這裡使用了匿名函數,實際應用中較常見}構造無參數的函數名引用,因為閉包的函數一般沒有參數
//使用之前 outer 函數的例子var clos=outer("Wang");setTimeout(clos,100);模組封裝,比如在 jQuery 中就有類似的代碼,保證內部變數不影響全域變數
function($){ // jQuery 內部實現})(jQuery); // 這裡使用了自動執行的匿名函數,即定義匿名函數並立即執行。看起來和閉包沒什麼關係,但原來是一樣的。
但是,閉包最好要少用,之前已經說過,閉包會使變數始終儲存在記憶體中,如果不當使用會增大記憶體開銷,甚至會帶來記憶體流失的風險。當然,還是可以使用類似
//使用之前 outer 函數的例子clos=null;的代碼釋放變數佔用的記憶體並協助 GC 機制回收。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.