在下面的例子中,为什么点击所有的段落p输出都是5,而不是alert出对应的0,1,2,3,4。
1 <html> 2 <head> 3 <meta charset="utf-8" /> 4 <title>闭包演示</title> 5 <style type="text/css"> 6 p {background:#ccc;} 7 </style> 8 <script type="text/javascript"> 9 window.onload = function() { 10 var arr= document.getElementsByTagName("p"); 11 for( var i=0; i<arr.length; i++ ) { 12 arr[i].onclick = function() { 13 alert(i); 14 } 15 } 16 } 17 </script> 18 </head> 19 <body> 20 <p>000</p> 21 <p>111</p> 22 <p>222</p> 23 <p>333</p> 24 <p>444</p> 25 </body> 26 </html>
原因是初学者并未理解JavaScript的闭包特性。通过element.onclick=function(){alert(i);}方式给元素添加 点击事件。响应函数function(){alert(i);}中的 i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值 i,而是最后一次i++的值5。
方法1:将变量 i 保存给在每个段落对象(p)上
1 window.onload = function(){ 2 var arr = document.getElementsByTagName('p'); 3 for(var i=0; i<arr.length; i++){ 4 arr[i].i= i; //或 arr[i].index = i; 5 arr[i].onclick = function(){ 6 alert(this.i); //或alert(this.index); 7 } 8 } 9 }
方法2:加一层闭包,i 以函数参数形式传递给内层函数
window.onload = function () { var arr= document.getElementsByTagName("p"); for( var i=0; i<pAry.length; i++ ) { (function(arg){ arr[i].onclick = function() { alert(arg); }; })(i);//调用时参数 } }
方法3:将变量 i 保存在匿名函数自身
1 window.onload = function () { 2 var arr= document.getElementsByTagName("p"); 3 for( var i=0; i<arr.length; i++ ) { 4 (arr[i].onclick = function() { 5 alert(arguments.callee.i); 6 }).i = i; 7 } 8 }
4、加一层闭包,i 以局部变量形式传递给内层函数
1 window.onload = function () { 2 var arr= document.getElementsByTagName("p"); 3 for( var i=0; i<arr.length; i++ ) { 4 (function () { 5 var temp = i;//调用时局部变量 6 arr[i].onclick = function() { 7 alert(temp); 8 } 9 })(); 10 } 11 }
5、加一层闭包,返回一个函数作为响应事件(注意与2的细微区别)
1 window.onload = function () { 2 var arr= document.getElementsByTagName("p"); 3 for( var i=0; i<arr.length; i++ ) { 4 arr[i].onclick = function(arg) { 5 return function() {//返回一个函数 6 alert(arg); 7 } 8 }(i); 9 } 10 }
6、用Function实现,实际上每产生一个函数实例就会产生一个闭包
1 window.onload = function() { 2 var arr= document.getElementsByTagName("p"); 3 for( var i=0; i<arr.length; i++ ) { 4 arr[i].onclick = new Function("alert(" + i + ");"); //new一次就产生一个函数实例 5 } 6 }
7、用Function实现,注意与6的区别
1 window.onload = function() { 2 var arr= document.getElementsByTagName("p"); 3 for( var i=0; i<arr.length; i++ ) { 4 arr[i].onclick = Function('alert('+i+')'); 5 } 6 }