题主的 for 循环跑完后,实际上:
i=5
btn = 最后一个 input
为什么这样呢,我们来看下代码,稍微改了下:
for(var i=0;i<5;i++){
var btn=document.createElement('input');
btn.setAttribute('type','button');
btn.setAttribute('value','btn'+i);
document.body.insertBefore(btn,document.body.firstElementChild); //直接插入到文档最前面,方便测试
btn.onclick=function(){
alert(btn.value);
};
}
要知道 es6 之前是没有块级作用域的,且
用 var 定义的变量会有一个声明提升的特性,这个动作开始于代码执行之前,会将 var 定义的变量提升到所在函数或全局环境的顶端,但是赋值操作仍然停留在原地
题主的代码其实相当于:
var i,btn;
for(i=0;i<5;i++){
btn=document.createElement('input');
btn.setAttribute('type','button');
btn.setAttribute('value','btn'+i);
document.body.insertBefore(btn,document.body.firstElementChild);
btn.onclick=function(){
alert(btn.value);
};
}
console.log(btn); // btn 被赋值了5次,覆盖了4次,最后一个是 btn4,所以很显然是最后一个
console.log(i); // i=5的时候跳出循环,所以 i 最后一个值是 5
这样是不是就很好理解了?
因为你给 btn 绑定的事件处理程序(回调函数)并不是马上执行,触发的时候才执行,这个时候 btn 已经被覆盖了4次,变成最后一个 btn 了;
核心原因是: var 有声明提前的特性。如要改的话,有多种方式,这里暂就说两种:
法一:btn 改为 this (推荐)
for(var i=0;i<5;i++){
var btn=document.createElement('input');
btn.setAttribute('type','button');
btn.setAttribute('value','btn'+i);
document.body.insertBefore(btn,document.body.firstElementChild);
btn.onclick=function(){
alert(this.value);
};
}
在事件绑定中,如果事件处理程序(也就是回调函数)中没有嵌套的函数,事件绑定在谁身上,this 就指向谁,如果回调里还有嵌套函数,this 默认指向全局对象,所以这里 this 就指向了绑定时的那个 btn;不明白戳这
法二:用 let 代替 var
for(var i=0;i<5;i++){
let btn=document.createElement('input');
btn.setAttribute('type','button');
btn.setAttribute('value','btn'+i);
document.body.insertBefore(btn,document.body.firstElementChild);
btn.onclick=function(){
alert(btn.value);
};
}
这是 ES6 的内容,详细理解戳这:深入理解ES6-中
10 回答11.1k 阅读
6 回答3k 阅读
5 回答4.8k 阅读✓ 已解决
4 回答3.1k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
3 回答5.1k 阅读✓ 已解决
5 回答1.9k 阅读