書接
上回,繼續(xù)閉包。
Closures
1、自動(dòng)的垃圾回收?? ECMAScript有自動(dòng)的垃圾回收機(jī)制。與java類似。但是規(guī)范也沒有對(duì)該機(jī)制詳細(xì)定義,而是讓瀏覽器等規(guī)范實(shí)現(xiàn)廠家來實(shí)現(xiàn),各種瀏覽器實(shí)現(xiàn)不一樣,垃圾回收的算法也不同。好象ie的實(shí)現(xiàn)會(huì)出現(xiàn)內(nèi)存溢出問題。對(duì)我我們來說注意到這點(diǎn)就夠了,后面會(huì)提到如何避免ie的這個(gè)bug.
?? 關(guān)于上篇提到的execution context,調(diào)用對(duì)象,參數(shù),scope chain 等等都需要內(nèi)存,垃圾回收機(jī)制會(huì)在適當(dāng)時(shí)候釋放內(nèi)存。
2、閉包如何形成?? 通俗的說,當(dāng)一個(gè)(outer)函數(shù)的返回類型是(inner)函數(shù)類型時(shí),這個(gè)被返回的inner函數(shù)斥又outer函數(shù)的scope chain,這時(shí)候閉包形成。? 如下例:
function exampleClosureForm(arg1, arg2){
??? var localVar = 8;
??? function exampleReturned(innerArg){
??????? return ((arg1 + arg2)/(innerArg + localVar));
??? }
??? /* return a reference to the inner function defined as -
?????? exampleReturned -:-
??? */
??? return exampleReturned;
}
var globalVar = exampleClosureForm(2, 4);
? 現(xiàn)在exampleClosureForm(2, 4)返回的inner函數(shù)不能被垃圾回收,因?yàn)樗蛔兞縢lobalVar持有,并可執(zhí)行g(shù)lobalVar(n)。
? 但是內(nèi)部的原理沒有表面上那么簡(jiǎn)單。現(xiàn)在globalVar是個(gè)函數(shù)對(duì)象,它的[[scope]] property 指向一個(gè)scope chain,而這個(gè)scope chain 包括?? exampleClosureForm函數(shù)的調(diào)用對(duì)象+global對(duì)象。所以垃圾回收不能回收這部分內(nèi)存。
? 一個(gè)閉包形成了。inner函數(shù)對(duì)象有自己的變量,也可以訪問exampleClosureForm函數(shù)調(diào)用過程中的參數(shù),local變量等。
? 在上面的例子中,globalVar(n)執(zhí)行時(shí),在通過調(diào)用對(duì)象可以訪問到exampleClosureForm(2, 4)執(zhí)行過程中的參數(shù),local變量等。arg1 = 2,arg2 = 4 ,localVar=8,這些屬性都通過調(diào)用對(duì)象"ActOuter1"可以得到。
如果增加以下代碼,又返回另外一個(gè)inner 函數(shù)。
var secondGlobalVar = exampleClosureForm(12, 3);
exampleClosureForm(12, 3)會(huì)引起新的調(diào)用對(duì)象創(chuàng)建,我們定義為ActOuter2。這個(gè)過程中,arg1 = 12,arg2 = 3 ,localVar=8。第二個(gè)閉包形成了.
?? 下面考慮返回的inner函數(shù)執(zhí)行過程。如globalVar(2)。新的execution context、調(diào)用對(duì)象(ActInner)被創(chuàng)建。現(xiàn)在的scope chain是? ActInner1->ActOuter1->global object.? 函數(shù)返回是 ((2 + 4)/(2 + 8)).
??? 如果是secondGlobalVar(5)被執(zhí)行情況是什么呢?現(xiàn)在的scope chain是ActInner2-> ActOuter2-> global object.函數(shù)返回是 ((12 + 3)/(5 + 8)).
??? 通過比較,這兩個(gè)inner函數(shù)互不干擾的執(zhí)行。如果嵌套更多的函數(shù)的話,與上面所訴類似。明白的javascript的閉包,從這個(gè)方面可能就能體會(huì)到它比java等慢n個(gè)數(shù)量級(jí)的原因。
3、閉包能做什么(例子)(1)function callLater(paramA, paramB, paramC){
??? return (function(){
??????? paramA[paramB] = paramC;
??? });
}
var functRef = callLater(elStyle, "display", "none");
hideMenu=setTimeout(functRef, 500);
想象我們做顏色漸變,或者動(dòng)畫的時(shí)候吧。上面提供的函數(shù)多幽雅。
(2)function associateObjWithEvent(obj, methodName){
??? return (function(e){
??????? e = e||window.event;
??????? return obj[methodName](e, this);
??? });
}
function DhtmlObject(elementId){
??? var el = getElementWithId(elementId);
??? if(el){
??????? el.onclick = associateObjWithEvent(this, "doOnClick");
??????? el.onmouseover = associateObjWithEvent(this, "doMouseOver");
??????? el.onmouseout = associateObjWithEvent(this, "doMouseOut");
??? }
}
DhtmlObject.prototype.doOnClick = function(event, element){
??? ... // doOnClick method body.
}
DhtmlObject.prototype.doMouseOver = function(event, element){
??? ... // doMouseOver method body.
}
DhtmlObject.prototype.doMouseOut = function(event, element){
??? ... // doMouseOut method body.
}
......
又一種注冊(cè)事件的方法。我覺得作者的這種實(shí)現(xiàn)可謂精妙。大大的開闊了我的思路。我們可以為我們的UI事件綁定到對(duì)象上,可以很好的重用代碼。另外比起prototype.js的時(shí)間注冊(cè)來說簡(jiǎn)單點(diǎn)。
(3)var getImgInPositionedDivHtml = (function(){
??? var buffAr = [
??????? '<div id="',
??????? '',?? //index 1, DIV ID attribute
??????? '" style="position:absolute;top:',
??????? '',?? //index 3, DIV top position
??????? 'px;left:',
??????? '',?? //index 5, DIV left position
??????? 'px;width:',
??????? '',?? //index 7, DIV width
??????? 'px;height:',
??????? '',?? //index 9, DIV height
??????? 'px;overflow:hidden;\"><img src=\"',
??????? '',?? //index 11, IMG URL
??????? '\" width=\"',
??????? '',?? //index 13, IMG width
??????? '\" height=\"',
??????? '',?? //index 15, IMG height
??????? '\" alt=\"',
??????? '',?? //index 17, IMG alt text
??????? '\"><\/div>'
??? ];
??? return (function(url, id, width, height, top, left, altText){
??????? buffAr[1] = id;
??????? buffAr[3] = top;
??????? buffAr[5] = left;
??????? buffAr[13] = (buffAr[7] = width);
??????? buffAr[15] = (buffAr[9] = height);
??????? buffAr[11] = url;
??????? buffAr[17] = altText;
??????? return buffAr.join('');
??? }); //:End of inner function expression.
})();
這種匿名函數(shù)的調(diào)用在dojo中見過,現(xiàn)在再看,感覺不一樣。
以上是原作者的例子,我抄過來的。下次我準(zhǔn)備深入研究一下閉包能給我們開發(fā)js類庫(kù)提供什么更好的思路。感覺現(xiàn)在很多人對(duì)閉包了解不多,經(jīng)過這段時(shí)間的思考,利用javascript中的閉包,代碼偶合性會(huì)更低。