闭包用法:经典案例

闭包用法:经典案例

学习一样技能,最终是想把它投入运用。我们从JS函数的最基础用法,一直研究到作用域链、闭包,这个过程消耗了我们大量的心血,那么闭包到底能用在哪些场景里面呢?下面将使用逐个枚举的方式给出运用闭包的典型战例。

请注意,以下的例子都是应用闭包的典型场景,当然如果你愿意,也可以把它叫做“代码模式”。深入理解,甚至记住这些场景,将会让你的闭包技法如有神助。

获取Table中被点击的行

例4.53

代码:

<html>

<title>Ext江湖</title>

<metahttp-equiv="Content-Type" content="text/html" ;charset="utf-8">

<scripttype="text/javascript"src="closure_example.js"></script>

<bodyοnlοad="myEffect()">

<tableid="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>

<divid="console" style="background:#ffff00"></div>

</body>

</html>

closure_example.js的代码如下:

function myEffect(){

varconsole=document.getElementById('console');

vartab=document.getElementById('mytab');

vartrs=tab.getElementsByTagName('tr');

for(vari=0;i<trs.length;i++){

vartr=trs[i];

tr.οnmοuseοver=function(){

this.style.background="#ff0000";

}

tr.οnmοuseοut=function(){

this.style.background="#ffffff";

}

tr.οnclick=(function(){

varrowNum=i;

returnfunction(){

console.innerHTML="点击了第"+rowNum+"行";

}

})();

}

}

解析:

因为有这一句<body οnlοad="myEffect()">,所以在body加载完成之后,myEffect()这个函数就被执行。myEffect做的事情很简单,它给每一个tr标签都添加了3个事件监听函数:onmouserover、onmouseout、onclick。前两个函数非常简单,无须解释。亮点在于第3个函数:

tr.οnclick=(function(){

varrowNum=i;

returnfunction(){

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>

<metahttp-equiv="Content-Type" content="text/html" ;charset="utf-8">

<body>

<buttonname="添加线程" value="添加线程" οnclick="addThread()">添加

线程</button>

</body>

<scripttype="text/javascript"src="sim_thread.js"></script>

</html>

脚本代码:

//这里是一个简单的DIV工具,用来创建DIV

function DivUtil(){}

DivUtil.prototype.counter=0;

DivUtil.prototype.creatDiv=function(){

vardiv=document.createElement('div');

div.style.background='#ffff00';

div.id=this.counter++;

document.body.appendChild(div);

returndiv;

}

vardivUtil=new DivUtil();

//这里是“线程”类

Thread=function(){}

Thread.prototype.start=function(){

vardiv=divUtil.creatDiv();

if(div.id>=10){

div.innerHTML="只允许起10个线程,看看你的CPU,撑到爆!";

return;

}

varnum=div.id;

setInterval(function(){

div.innerHTML="第"+div.id+"个线程运行中..."+(num++);

},50);

}

//工具函数,添加线程

functionaddThread(){

varthread=new Thread();

thread.start();

}

运行效果如图4-91所示。

图4-91 模拟多线程

解析:

这是一个非常有趣的例子,看起来就像启动了多个“线程”,核心的代码是这段:

var num=div.id;

setInterval(function(){

div.innerHTML="第"+div.id+"个线程运行中..."+(num++);

},50);

因为闭包的缘故,在定时器setInterval所执行的函数中,可以一直访问外层函数中的局部变量num。

——本段文字节选自《EXT江湖》

图书详细信息:http://blog.csdn.net/broadview2006/article/details/7211734

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值