javascript中循环添加事件时的闭包问题解决

这是一个经典问题,只不过有一段时间不写纯js了,最近老是掉进以前跌过的坑,这次花了半天时间爬出来,所以记录一下。

 

昨天写js代码在给自定义的div注册onclick事件时发现得到的值始终是循环里的最后一个层里的值。

最早的代码:

 

for(var i in array){
	var rowDiv = document.createElement("div");
	rowDiv.innerText = array[i]["name"];
	rowDiv.onclick = function(){//注册点击事件
		pNode = this.parentNode;
		pNode.previousSibling.value = this.innerText;//将当前div的值赋给输入框
		if(onclickCallback){//传入了回调函数则执行回调
			onclickCallback(array[i]);
		}
	};
}

 

为了不干扰阅读的视线,将与这个问题无关的代码直接裁掉:

 

for(var i in array){
	var rowDiv = document.createElement("div");
	rowDiv.innerText =array[i];
	rowDiv.onclick = function(){//注册点击事件
		alert(array[i]);
	};
}

 

这里发现点击一个div之后alert出来的始终是最后一次循环的值。这个现象立马想起来这是一个经典的闭包问题,在执行onclick的事件时会向外部函数寻找array[i]的定义,这里的i在for循环执行完之后变成了array[array.length-1]。

 

网上搜了一下,改进的方法有很多种:

方法1,外层包一个匿名函数,将每次循环的索引结果作为入参传入并自执行:

 

for(var i in array){
	(function(obj){
		var rowDiv = document.createElement("div");
		rowDiv.innerText = obj;
		rowDiv.onclick = function(){//注册点击事件
			alert(obj);
		};
	})(array[i]);
}

 

方法2,同样是利用闭包,给innerText赋值部分并没有问题,有问题的只是用到了闭包特性的onclick事件注册部分,所以就改onclick部分:

 

for(var i in array){
	var rowDiv = document.createElement("div");
	rowDiv.innerText = array[i];
	rowDiv.onclick = (function(obj){//注册点击事件
		return function(){
			alert(obj);
		};
	})(array[i]);
}

 

方法3,以上解决翻案的语法看起来挺晦涩,但都是在闭包里打转,个人觉得能不用闭包的地方就尽量别用,一个不小心就会碰上内存泄漏的问题。下面给出另一种解法:

for(var i in array){
	var rowDiv = document.createElement("div");
	rowDiv.innerText = array[i];
	rowDiv.obj = array[i];
	rowDiv.onclick = function(){//注册点击事件
		alert(this.obj);
	};
}

这是我个人认为较好的方案,给dom对象添加自定义属性来保存值,在div的事件触发时可以通过this来引用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值