Javascript闭包演示

本文探讨了JavaScript中闭包的使用误区,特别是在为多个DOM元素动态绑定事件处理程序时出现的问题。通过具体示例解释了为何点击不同元素时会得到相同的响应,并提供了多种解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

01 <!DOCTYPE HTML>
02 < html >
03 < head >
04 < meta charset = "utf-8" />
05 < title >闭包演示</ title >
06 < style type = "text/css" >
07      p {background:gold;}
08 </ style >
09 < script type = "text/javascript" >
10 function init() {   
11      var pAry = document.getElementsByTagName("p");   
12      for( var i=0; i< pAry.length ; i++ ) {   
13           pAry[i] .onclick = function () {   
14           alert(i);   
15      }
16    }
17 }
18 </script>
19 </ head >
20 < body onload = "init();" >
21 < p >产品 0</ p >
22 < p >产品 1</ p >
23 < p >产品 2</ p >
24 < p >产品 3</ p >
25 < p >产品 4</ p >
26 </ body >
27 </ html >


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

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


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

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

1 function init1() {
2    var pAry = document.getElementsByTagName( "p" );
3    for ( var i=0; i<pAry.length; i++ ) {
4       pAry[i].i = i;
5       pAry[i].onclick = function () {
6          alert( this .i);
7       }
8    }
9 }

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

1 function init2() {
2    var pAry = document.getElementsByTagName( "p" );
3    for ( var i=0; i<pAry.length; i++ ) {
4     (pAry[i].onclick = function () {
5          alert(arguments.callee.i);
6      }).i = i;
7    }
8 }

 

后又想到了三种

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

01 function init3() {
02    var pAry = document.getElementsByTagName( "p" );
03    for ( var i=0; i<pAry.length; i++ ) {
04     ( function (arg){
05         pAry[i].onclick = function () {
06            alert(arg);
07         };
08     })(i); //调用时参数
09    }
10 }

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

01 function init4() {
02    var pAry = document.getElementsByTagName( "p" );
03    for ( var i=0; i<pAry.length; i++ ) {
04      ( function () {
05        var temp = i; //调用时局部变量
06        pAry[i].onclick = function () {
07          alert(temp);
08        }
09      })();
10    }
11 }

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

01 function init5() {
02    var pAry = document.getElementsByTagName( "p" );
03    for ( var i=0; i<pAry.length; i++ ) {
04     pAry[i].onclick = function (arg) {
05         return function () { //返回一个函数
06         alert(arg);
07       }
08     }(i);
09    }
10 }

 

后又发现了两种

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

1 function init6() {
2      var pAry = document.getElementsByTagName( "p" );
3      for ( var i=0; i<pAry.length; i++ ) {
4        pAry[i].onclick = new Function( "alert(" + i + ");" ); //new一次就产生一个函数实例
5      }
6 }

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

1 function init7() {
2      var pAry = document.getElementsByTagName( "p" );
3      for ( var i=0; i<pAry.length; i++ ) {
4           pAry[i].onclick = Function( 'alert(' +i+ ')' );
5      }
6 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值