引子:關於閉包
什么是閉包呢?
從定義上來看,所有的函數都可以是閉包。當一個函數在調用時,引用了不是自己作用域內定義的變量(通常稱其為自由變量),則形成了閉包;閉包是代碼塊和創建該代碼塊的上下文中數據的結合。
例子: 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:定義:
globalContext
];
];
1、作用域鏈
首先,我們如何創建一個作用域呢,function()。函數是javascript中唯一一個能創建出作用域的,也就是說for、if、while的{}是不能創建出作用域的。區別c++中的塊作用域{}。
一個函數的作用域創建后,將貫穿他的始“{”,終“}”,作用域
。這句話就應該着重理解貫穿2字了,若函數內部嵌套着多個函數,那么從最內層函數作用域依次往外就形成了作用鏈。
ps:需要我們理解作用域鏈的變量查找機制是由內往外的。先找自身作用域,再一次往外,若沒有,則等同沒有var時的聲明(為全局添加了一個屬性);
2、變量對象(Variable Object)、活動對象(Activation Object)
瀏覽器在對代碼進行解析時,會先進行變量聲明和函數聲明以及函數形參聲明;
(全局作用域下)那么這些優先聲明的變量儲存在哪里呢?
沒錯,就在變量對象中(抽象概念);活動對象怎么理解呢?
(VO === this === global)
--> 函數上下文變量對象FunctionContextVO
(VO === AO, 並且添加了<arguments>(形參類數組)和<formal parameters>(形參的值))
ps:在函數執行上下文中,VO是不能直接訪問的,此時由活動對象扮演VO的角色。Arguments對象是活動對象的一個屬性,它包括如下屬性:
-
callee — 指向當前函數的引用
-
length — 真正傳遞的參數個數
-
properties-indexes (字符串類型的整數) 屬性的值就是函數的參數值(按參數列表從左到右排列)。 properties-indexes內部元素的個數等於arguments.length. properties-indexes 的值和實際傳遞進來的參數之間是共享的。
現在讓我們來串一下
1、全局執行上下文
創建global.VO
2、全局變量的賦值 | 調用函數()(激活)
激活函數后,會得到當前的AO,其中有內部函數的聲明、內部變量的聲明、形參
3、進入所激活的函數的上下文
進行所在作用域鏈上的變量的賦值 各種運算 (作用域鏈包含全局的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