首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > JavaScript >

Javascript闭包演练

2012-11-25 
Javascript闭包演示有个网友问了个问题,如下的html,为什么点击所有的段落p输出都是5,而不是alert出对应的0

Javascript闭包演示

有个网友问了个问题,如下的html,为什么点击所有的段落p输出都是5,而不是alert出对应的0,1,2,3,4。

<!DOCTYPEHTML><html><head><meta charset="utf-8"/><title>闭包演示</title><style type="text/css">????p{background:gold;}</style><script type="text/javascript">function init(){???????varpAry =document.getElementsByTagName_r("p");???????for(var i=0; i<pAry.length; i++ ){????????????pAry[i].onclick= function(){????????????alert(i);???????}??}}</script></head><body onload="init();"><p>产品0</p><p>产品1</p><p>产品2</p><p>产品3</p><p>产品4</p></body></html>

以上场景是初学者经常碰到的。即获取HTML元素集合,循环给元素添加事件。在事件响应函数中(eventhandler)获取对应的索引。但每次获取的都是最后一次循环的索引。

原因是初学者并未理解JavaScript的闭包特性。通过element.onclick=function(){alert(i);}方式给元素添加点击事件。响应函数function(){alert(i);}中的i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值i,而是最后一次i++的值5。


了解了原因,摸索出了很多解决办法(纯粹是兴趣)。最先想到的前两种

1、将变量 i 保存给在每个段落对象(p)上

unction init1() {??varpAry =document.getElementsByTagName_r("p");??for(var i=0; i<pAry.length; i++ ){?????pAry[i].i = i;?????pAry[i].onclick= function() {????????alert(this.i);?????}??}}

2、将变量 i 保存在匿名函数自身

function init2() {??varpAry =document.getElementsByTagName_r("p");??for(var i=0; i<pAry.length; i++ ){???(pAry[i].onclick = function() {????????alert(arguments.callee.i);????}).i= i;??}}

后又想到了三种

3、加一层闭包,i 以函数参数形式传递给内层函数

function init3() {??varpAry =document.getElementsByTagName_r("p");??for(var i=0; i<pAry.length; i++ ){???(function(arg){???????pAry[i].onclick= function() {??????????alert(arg);???????};???})(i);//调用时参数??}}

4、加一层闭包,i 以局部变量形式传递给内层函数

function init4() {??varpAry =document.getElementsByTagName_r("p");??for(var i=0; i<pAry.length; i++ ){????(function() {??????var temp =i;//调用时局部变量??????pAry[i].onclick= function() {????????alert(temp);??????}????})();??}}

5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)

?

function init5() {??varpAry =document.getElementsByTagName_r("p");??for(var i=0; i<pAry.length; i++ ){???pAry[i].onclick = function(arg) {???????returnfunction() {//返回一个函数???????alert(arg);?????}???}(i);??}

}

后又发现了两种

6、用Function实现,实际上每产生一个函数实例就会产生一个闭包

function init6() {????varpAry =document.getElementsByTagName_r("p");????for(var i=0; i<pAry.length; i++ ){??????pAry[i].onclick= new Function("alert(" + i + ");");//new一次就产生一个函数实例????}}

7、用Function实现,注意与6的区别

function init7() {????varpAry =document.getElementsByTagName_r("p");????for(var i=0; i<pAry.length; i++ ){?????????pAry[i].onclick= Function('alert('+i+')');????}}

New Function() 与Function()的区别:
情景一:
var yx01 = new function() {return "圆心"};
alert(yx01);
我们运行情景一代码,将返回显示“[object object]”,此时该代码等价于:

function 匿名类(){
return "圆心";
}
var yx01 = new 匿名类();
alert(yx01);我们对情景一的代码进行下面改造:

var yx01 = new function() {return new String("圆心")};
alert(yx01);
我们运行,将会发现返回的是“圆心”,这是为什么呢?

只 要 new表达式之后的 constructor返回(return)一个引用对象(数组,对象,函数等),都将覆盖new创建的匿名对象,如果返回(return)一个原始类型(无return 时其实为 return 原始类型 undefined),那么就返回 new 创建的匿名对象
由于 new String 会构造一个对象,而不是一个 string 直接量,且new String(x)如果带参数,那么alert它的时候就会返回 x。所以 yx01 将返回 new String(”圆心”) 这个对象,而 alertyx01 则显示 “圆心”。

情景二:

var yx02 = function() {return "圆心"}();
alert(yx02);我们运行情景二代码,将返回显示“圆心”,此时该代码等价于:

var 匿名函数 =function() {return "圆心"};
yx02 =匿名函数();
alert(yx02);很明显,yx02 返回的是匿名函数的执行结果值,即 yx02 为:“圆心”。

当然匿名函数的执行结果也可以为一个匿名对象。具体常见应用可以看《Javascript的一种模块模式》

热点排行
Bad Request.