由于js词法性质和全局变量被更改,循环绑定的click事件执行时变量和定义时 不一致的bug,各种解决方案。
动态在页面上添加了5个按钮,实现的功能应该是点击对应按钮在控制台输出相应的索引。但因为应该是i的变量应该一直指引的对应的地址,所以一直输出的是5.就是想请教您一下,这种问题应该是怎么样的一个解决思路。您要是有时间的时候帮我看下。非常感谢!
问题:
//这个有bug,一直输出5
for (var i =0 ; i<5 ; i++){
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Button"+i));
btn.addEventListener("click",function(){
console.log(i);
});
document.body.appendChild(btn);
}
错误解法一:
(虽然定义了新变量 ,避免了使用全局的i,但是,新变量一直被重新定义,最终定义为和最新的i保持一样了 )
for (var i =0 ; i<5 ; i++){
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Button"+i));var j=i;
btn.addEventListener("click",function(){
console.log(j);
});
document.body.appendChild(btn);
} //一直输出4
错误解法二:
(所谓闭包)
for (var i =0 ; i<5 ; i++){
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Button"+i));
btn.addEventListener("click",function(){
var result = function (num){
return function(){
return num;
}
}(i);
console.log(result);
}
);
document.body.appendChild(btn);
}
解决方法一:
for (var i =0 ; i<5 ; i++){
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Button"+i));
btn.id="btn_"+i;
btn.addEventListener("click",function(){
console.log(this.id.split("_")[1]);
});
document.body.appendChild(btn);
}
解决方法二:
for (var i =0 ; i<5 ; i++){
var btn = document.createElement("button");
!function(i){
btn.appendChild(document.createTextNode("Button"+i));
btn.addEventListener("click",function(){
console.log(i);
});
}(i);
document.body.appendChild(btn);
}
1 for (var i =0 ; i<5 ; i++){
2 var btn = document.createElement("button");
3 (function(i){
4 btn.appendChild(document.createTextNode("Button"+i));
5 btn.addEventListener("click",function(){
6 console.log(i);
7 });
8 })(i);
9 document.body.appendChild(btn);
10 }
总结:
两种闭包方案,为何一个错,一个对?
虽然都是闭包,但是你的没有把需要的东西给关闭进去,因为你的范围太小,你关时,人家已经是5 了。
两种正确做法有何区别?
而他们的写法是,在没成5时,就关闭进去,这样就保护了变量的中间值,他们存在闭包内,而另一种存在dom上,异曲同工之妙,都达到了中间值的保存。