闭包用法:经典案例
閉包用法:經典案例
學習一樣技能,最終是想把它投入運用。我們從JS函數的最基礎用法,一直研究到作用域鏈、閉包,這個過程消耗了我們大量的心血,那么閉包到底能用在哪些場景里面呢?下面將使用逐個枚舉的方式給出運用閉包的典型戰例。
請注意,以下的例子都是應用閉包的典型場景,當然如果你愿意,也可以把它叫做“代碼模式”。深入理解,甚至記住這些場景,將會讓你的閉包技法如有神助。
獲取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>
??????????????????????????? //這里重復5個<tr>,結構和上面一樣
?????????????????? </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()這個函數就被執行。myEffect做的事情很簡單,它給每一個tr標簽都添加了3個事件監聽函數:onmouserover、onmouseout、onclick。前兩個函數非常簡單,無須解釋。亮點在于第3個函數:
?
tr.οnclick=(function(){
???????? var rowNum=i;
???????? return function(){
?????????????????? console.innerHTML="點擊了第"+rowNum+"行";
???????? }
})();
從整體看,這是一個“自執行”函數,最終被注冊給onclick事件的是內部return的這個匿名函數。那么,為什么要這么做呢?比如,和上面兩個函數一樣,做成這樣可不可以呢?
tr.οnclick= function(){
???????? console.innerHTML="點擊了第"+i+"行";
};
注意,i是外層那個for循環里面定義的循環變量。你可以自己測試這個代碼,最終結果是:無論你點擊哪一行,結果都是“點擊了第6行”。那么為什么會出現這種結果呢?這是因為在for循環的過程中,i始終代表的是同一個變量。雖然你看似給每個tr都注冊了一個onclick函數,但是里面那個i最終指向的是同一個東西,它是隨著for循環變化的。所以,在for循環結束之后,i將會一直是6。那么如何在for循環結束之后,讓i一直保留for循環中對應的次序呢?這就是上面那個return函數的作用了。里面用一個局部變量var rowNum=i;把i的值“緩存”起來,然后即使外層的“自執行”函數退出,內部return出來的匿名函數仍然可以訪問到對應順序的值。
有了本章第3節對函數“作用域鏈”的研究,rowNum這個外層函數的局部變量被緩存在哪里,這種技法為什么能起作用,就無須多言了吧?
模擬多線程
例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工具,用來創建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);
???????? }
?
???????? //工具函數,添加線程
???????? 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所執行的函數中,可以一直訪問外層函數中的局部變量num。
?
——本段文字節選自《EXT江湖》
圖書詳細信息:
http://www.cnblogs.com/broadview/archive/2012/01/20/2327735.html總結
- 上一篇: Ubuntu安装amule和编译安装am
- 下一篇: 相同vlan跨交换机进行通信