Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1521923
  • 博文数量: 465
  • 博客积分: 8915
  • 博客等级: 中将
  • 技术积分: 6365
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-30 15:05
文章分类

全部博文(465)

文章存档

2017年(33)

2016年(2)

2015年(4)

2014年(29)

2013年(71)

2012年(148)

2011年(178)

分类: IT业界

2012-02-06 15:45:45

闭包用法:经典案例

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

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

获取Table中被点击的行

4.53

代码:

         Ext</FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-fareast-font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin">江湖</SPAN><SPAN lang=EN-US><FONT face=Calibri>

        

        

        

                  

                           

                                    

                                    

                                    

                                    

                                    

                           

                           

                                    

                                    

                                    

                                    

                                    

                           

                            //这里重复5

,结构和上面一样

                  

1 2 3 4 5
1 2 3 4 5

                  

        

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

                   var tr=trs[i];

                   tr.onmouseover=function(){

                            this.style.background="#ff0000";

                   }

                   tr.onmouseout=function(){

                            this.style.background="#ffffff";

                   }

                   tr.onclick=(function(){

                            var rowNum=i;

                            return function(){

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

                            }

                   })();

         }

}

解析:

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

 

tr.onclick=(function(){

         var rowNum=i;

         return function(){

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

         }

})();

从整体看,这是一个“自执行”函数,最终被注册给onclick事件的是内部return的这个匿名函数。那么,为什么要这么做呢?比如,和上面两个函数一样,做成这样可不可以呢?

tr.onclick= 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代码:

         </FONT></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-fareast-font-family: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin">模拟多线程</SPAN><SPAN lang=EN-US><FONT face=Calibri>

        

        

                  

        

        

脚本代码:

//这里是一个简单的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://blog.chinaunix.net/space.php?uid=13164110&do=blog&id=3060643

阅读(2056) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~