引子:關於閉包
什麼是閉包呢?
從定義上來看,全部的函數均可以是閉包。當一個函數在調用時,引用了不是本身做用域內定義的變量(一般稱其爲自由變量),則造成了閉包;閉包是代碼塊和建立該代碼塊的上下文中數據的結合。javascript
例子: function mytest( ){
var test=10;
return function( ){
test++;
alert(test);
}
}
var atest = new mytest( ); //引用返回的函數
atest( ); // 11
atest( ); // 12
ps:注意運用閉包的常見錯誤-->for(var i,len=xx.length;i<len;i++)循環;當咱們所引用的自由變量爲i時,因爲i一直在內存中沒有釋放,因此函數每次alert(i)時,其值均爲最終的i;(例子不少,就不寫了)
經過測試結果咱們能夠發現, 閉包會使該函數引用的變量一直在內存中,緣由是什麼呢?
簡單的解釋就是由於這個返回的函數引用了變量test;當瀏覽器解析到var atest=new mytest();這一行且mytes()函數執行完畢,準備內存釋放時,發現所返回的函數引用了test變量。從而該出棧的並無出去;
想徹底弄清楚這個問題,咱們還須要進一步理解AO(活動對象)和VO(變量對象)以及做用域鏈、執行上下文的問題。
那麼這整個機制瀏覽器究竟是怎麼解析的呢?
不急,咱們來看看執行上下文、做用域鏈、活動對象和變量對象;
寫在前面的執行上下文:
a:定義:html
一、做用域鏈
首先,咱們如何建立一個做用域呢,function()。函數是javascript中惟一一個能建立出做用域的,也就是說for、if、while的{}是不能建立出做用域的。區別c++中的塊做用域{}。
一個函數的做用域建立後,將貫穿他的始「{」,終「}」,做用域java
。這句話就應該着重理解貫穿2字了,若函數內部嵌套着多個函數,那麼從最內層函數做用域依次往外就造成了做用鏈。
ps:須要咱們理解做用域鏈的變量查找機制是由內往外的。先找自身做用域,再一次往外,若沒有,則等同沒有var時的聲明(爲全局添加了一個屬性);c++
二、變量對象(Variable Object)、活動對象(Activation Object)
瀏覽器在對代碼進行解析時,會先進行變量聲明和函數聲明以及函數形參聲明;
(全局做用域下)那麼這些優先聲明的變量儲存在哪裏呢?
沒錯,就在變量對象中(抽象概念);活動對象怎麼理解呢?設計模式
--> 函數上下文變量對象FunctionContextVO
(VO === AO, 而且添加了<arguments>(形參類數組)和<formal parameters>(形參的值))數組
ps:在函數執行上下文中,VO是不能直接訪問的,此時由活動對象扮演VO的角色。Arguments對象是活動對象的一個屬性,它包括以下屬性:瀏覽器
callee — 指向當前函數的引用閉包
length — 真正傳遞的參數個數函數
properties-indexes (字符串類型的整數) 屬性的值就是函數的參數值(按參數列表從左到右排列)。 properties-indexes內部元素的個數等於arguments.length. properties-indexes 的值和實際傳遞進來的參數之間是共享的。學習
如今讓咱們來串一下
一、全局執行上下文
建立global.VO
二、全局變量的賦值 | 調用函數()(激活)
激活函數後,會獲得當前的AO,其中有內部函數的聲明、內部變量的聲明、形參
三、進入所激活的函數的上下文
進行所在做用域鏈上的變量的賦值 各類運算 (做用域鏈包含全局的VO,和當前執行上下文的AO)
4.a、若在函數中有內部函數調用(或自執行),重複3;
4.b 若返回一個函數(或其引用),且該函數有對自由變量的引用-->造成閉包-->做用域鏈機制依然有效-->當前已壓入執行上下文堆棧的FunctionContext不會出棧;-->回到2;
4.c 正常return或正常結束,FunctionContext出棧;-->回到2;
5.全部代碼執行完畢,程序關閉,釋放內存。
寫在最後:
若是你是剛開始接觸javascript,若是你也相信博客園可以讓你的學習更加規劃與深刻,我推薦你看看王福鵬老師和湯姆大叔的博文,本身仔細揣摩,記錄下本身的感想,必定會有收穫的。加油。我正在努力看深刻系列的設計模式,感受看着不是很順,有些很差理解,但願有經驗的博主們能指點指點。這是個人第一篇博文,真心但願可以在博客園中尋到良師益友。
另貼上湯姆大叔深刻javascript系列博文的地址,
http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html