闭包用法:经典案例
閉包用法:經(jīng)典案例
學(xué)習(xí)一樣技能,最終是想把它投入運用。我們從JS函數(shù)的最基礎(chǔ)用法,一直研究到作用域鏈、閉包,這個過程消耗了我們大量的心血,那么閉包到底能用在哪些場景里面呢?下面將使用逐個枚舉的方式給出運用閉包的典型戰(zhàn)例。
請注意,以下的例子都是應(yīng)用閉包的典型場景,當(dāng)然如果你愿意,也可以把它叫做“代碼模式”。深入理解,甚至記住這些場景,將會讓你的閉包技法如有神助。
獲取Table中被點擊的行
例4.53
代碼:
<html>
???????? <title>Ext江湖</title>
???????? <meta http-equiv="Content-Type" content="text/html" ; charset="utf-8">
???????? <script type="text/javascript" src="closure_example.js"></script>
???????? <body οnlοad="myEffect()">
?????????????????? <table id="mytab" border="1">
??????????????????????????? <tr>
???????????????????????????????????? <td>第1列</td>
???????????????????????????????????? <td>第2列</td>
???????????????????????????????????? <td>第3列</td>
???????????????????????????????????? <td>第4列</td>
???????????????????????????????????? <td>第5列</td>
??????????????????????????? </tr>
??????????????????????????? <tr>
???????????????????????????????????? <td>1</td>
???????????????????????????????????? <td>2</td>
???????????????????????????????????? <td>3</td>
???????????????????????????????????? <td>4</td>
???????????????????????????????????? <td>5</td>
??????????????????????????? </tr>
??????????????????????????? //這里重復(fù)5個<tr>,結(jié)構(gòu)和上面一樣
?????????????????? </table>
?????????????????? <div id="console" style="background:#ffff00"></div>
???????? </body>
</html>
closure_example.js的代碼如下:
function myEffect(){
???????? var console=document.getElementById('console');
???????? var tab=document.getElementById('mytab');
???????? var trs=tab.getElementsByTagName('tr');
???????? for(var i=0;i<trs.length;i++){
?????????????????? var tr=trs[i];
?????????????????? tr.οnmοuseοver=function(){
??????????????????????????? this.style.background="#ff0000";
?????????????????? }
?????????????????? tr.οnmοuseοut=function(){
??????????????????????????? this.style.background="#ffffff";
?????????????????? }
?????????????????? tr.οnclick=(function(){
??????????????????????????? var rowNum=i;
??????????????????????????? return function(){
???????????????????????????????????? console.innerHTML="點擊了第"+rowNum+"行";
??????????????????????????? }
?????????????????? })();
???????? }
}
解析:
因為有這一句<body οnlοad="myEffect()">,所以在body加載完成之后,myEffect()這個函數(shù)就被執(zhí)行。myEffect做的事情很簡單,它給每一個tr標簽都添加了3個事件監(jiān)聽函數(shù):onmouserover、onmouseout、onclick。前兩個函數(shù)非常簡單,無須解釋。亮點在于第3個函數(shù):
?
tr.οnclick=(function(){
???????? var rowNum=i;
???????? return function(){
?????????????????? console.innerHTML="點擊了第"+rowNum+"行";
???????? }
})();
從整體看,這是一個“自執(zhí)行”函數(shù),最終被注冊給onclick事件的是內(nèi)部return的這個匿名函數(shù)。那么,為什么要這么做呢?比如,和上面兩個函數(shù)一樣,做成這樣可不可以呢?
tr.οnclick= function(){
???????? console.innerHTML="點擊了第"+i+"行";
};
注意,i是外層那個for循環(huán)里面定義的循環(huán)變量。你可以自己測試這個代碼,最終結(jié)果是:無論你點擊哪一行,結(jié)果都是“點擊了第6行”。那么為什么會出現(xiàn)這種結(jié)果呢?這是因為在for循環(huán)的過程中,i始終代表的是同一個變量。雖然你看似給每個tr都注冊了一個onclick函數(shù),但是里面那個i最終指向的是同一個東西,它是隨著for循環(huán)變化的。所以,在for循環(huán)結(jié)束之后,i將會一直是6。那么如何在for循環(huán)結(jié)束之后,讓i一直保留for循環(huán)中對應(yīng)的次序呢?這就是上面那個return函數(shù)的作用了。里面用一個局部變量var rowNum=i;把i的值“緩存”起來,然后即使外層的“自執(zhí)行”函數(shù)退出,內(nèi)部return出來的匿名函數(shù)仍然可以訪問到對應(yīng)順序的值。
有了本章第3節(jié)對函數(shù)“作用域鏈”的研究,rowNum這個外層函數(shù)的局部變量被緩存在哪里,這種技法為什么能起作用,就無須多言了吧?
模擬多線程
例4.54
HTML代碼:
<html>
???????? <title>模擬多線程</title>
???????? <meta http-equiv="Content-Type" content="text/html" ; charset="utf-8">
???????? <body>
?????????????????? <button name="添加線程" value="添加線程" οnclick="addThread()">添加
??????????????????????????? 線程</button>
???????? </body>
???????? <script type="text/javascript" src="sim_thread.js"></script>
</html>
腳本代碼:
//這里是一個簡單的DIV工具,用來創(chuàng)建DIV
function DivUtil(){}
???????? DivUtil.prototype.counter=0;
???????? DivUtil.prototype.creatDiv=function(){
?????????????????? var div=document.createElement('div');
?????????????????? div.style.background='#ffff00';
?????????????????? div.id=this.counter++;
?????????????????? document.body.appendChild(div);
?????????????????? return div;
???????? }
???????? var divUtil=new DivUtil();
?
???????? //這里是“線程”類
???????? Thread=function(){}
???????? Thread.prototype.start=function(){
?????????????????? var div=divUtil.creatDiv();
?????????????????? if(div.id>=10){
??????????????????????????? div.innerHTML="只允許起10個線程,看看你的CPU,撐到爆!";
??????????????????????????? return;
?????????????????? }
?????????????????? var num=div.id;
?????????????????? setInterval(function(){
??????????????????????????? div.innerHTML="第"+div.id+"個線程運行中..."+(num++);
?????????????????? },50);
???????? }
?
???????? //工具函數(shù),添加線程
???????? function addThread(){
?????????????????? var thread=new Thread();
?????????????????? thread.start();
???????? }
運行效果如圖4-91所示。
?
圖4-91? 模擬多線程
解析:
這是一個非常有趣的例子,看起來就像啟動了多個“線程”,核心的代碼是這段:
var num=div.id;
setInterval(function(){
???????? div.innerHTML="第"+div.id+"個線程運行中..."+(num++);
},50);
因為閉包的緣故,在定時器setInterval所執(zhí)行的函數(shù)中,可以一直訪問外層函數(shù)中的局部變量num。
?
——本段文字節(jié)選自《EXT江湖》
圖書詳細信息:
http://www.cnblogs.com/broadview/archive/2012/01/20/2327735.html總結(jié)
- 上一篇: Ubuntu安装amule和编译安装am
- 下一篇: 相同vlan跨交换机进行通信