JavaScript 循环中的闭包( for循环 i )
js和lua不一样,同样的代码在lua中,会分别打印出0,1,2,3,4,但是在js中只会打印5次4。
function init() {
var pAry = document.getElementsByTagName("p");
for( var i = 0; i < pAry.length; i++ ) {
pAry[ i ].onclick = function() {
alert( i );
}
}
}
即便写成如下形式也不行
function init() {
var pAry = document.getElementsByTagName("p");
for( var i = 0; i< pAry.length; i++ ) {
var temp = i;
pAry[ i ].onclick = function() {
alert( temp );
}
}
}
尽管每一次循环都新建了一个temp,但是都被循环最后一次的temp覆盖。总的来说js的变量作用域不是按照{}来区分的,而是按照函数来区分作用域,故for循环中的onclick函数是共享同一个域的。
(for循环中定义的变量在循环外也可以访问)
解决方式以下几种
1、将变量 i 保存给在每个段落对象(p)上
function init() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].i = i;
pAry[i].onclick = function() {
alert(this.i);
}
}
}
2、将变量 i 保存在匿名函数自身
function init2() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(pAry[i].onclick = function() {
alert(arguments.callee.i);
}).i = i;
}
}
再增加3种
3、加一层闭包,i以函数参数形式传递给内层函数
function init3() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(function(arg){
pAry[i].onclick = function() {
alert(arg);
};
})(i);//调用时参数
}
}
4、加一层闭包,i以局部变量形式传递给内存函数
function init4() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
(function () {
var temp = i;//调用时局部变量
pAry[i].onclick = function() {
alert(temp);
}
})();
}
}
5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
function init5() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = function(arg) {
return function() {//返回一个函数
alert(arg);
}
}(i);
}
}
又有一种方法
6、用Function实现,实际上每产生一个函数实例就会产生一个闭包
function init6() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = new Function("alert(" + i + ");");//new每次产生一个实例
}
}
再增加一种
7、用Function实现,注意与6的区别
function init7() {
var pAry = document.getElementsByTagName("p");
for( var i=0; i<pAry.length; i++ ) {
pAry[i].onclick = Function('alert('+i+')')
}
}