HTML:
<button class="btn">点击</button>
<button class="btn">点击</button>
<button class="btn">点击</button>
js:
<span style="white-space:pre"> </span>var btn=document.getElementsByClassName('btn');
for(var i=0,len=btn.length;i<len;i++){
btn[i].οnclick=function(){
console.log(i); // 3,3,3
}
}
方案一:
解决思路:
增加若干个对应的闭包域空间(这里采用的是匿名函数)
专门用来存储原先需要引用的内容(下标),不过只限于基本类型
(基本类型值传递,引用类型引用传递)
<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
//声明一个匿名函数,若穿进来的是基本类型则为值传递,故不对实参产生影响
(function(arg){
btn[i].οnclick=function(){// onclick函数实例的function scope的closure对象属性有一个引用arg,只要外部空间的arg不变,这里的引用值也不会改变
console.log(arg);
}
})(i); // 立即执行该匿名函数,传递下标i(实参)
}
解决思路二:
将下标作为对象属性(name:'i',value:i的值)添加到每个数组项中为当前数组项目即当前button对象添加一个名为i的属性,值为循环体的i变量的值;
此时当前button的对象的i属性并不是循环体i变量的引用,而是一个独立button对象的属性,属性值在声明的时候就确定了;
(基本类型的值都存在栈内存中,当有一个基本类型变量声明等于另一个基本变量时,此时并不是两个基本类型变量都指向了一个值,而是各自有各自的值,不过这两个值是相等的)
<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
btn[i].i=i;
btn[i].οnclick=function(){
console.log(this.i);
}
}
解决思路三:
与解决方法一相似但又有点不太相似。相似点:同样是增加个若干个对应的闭包域空间来存储下标;
不同点:解决方法一是在新增的匿名闭包空间内完成事件的绑定,而此例是将事件绑定在新增的的匿名函数返回的函数上
此时绑定的函数中 function scope中的closure对象的引用arg是指向讲其返回的匿名函数的私有变量arg
<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
btn[i].οnclick=(function(arg){
return function(){
console.log(arg);
}
})(i)
}
解决方法四:
与方法一相似<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
(function(){
var temp=i;
btn[i].οnclick=function(){
console.log(temp);
}
})()
}
解决方法五:
与方法三和四相似<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
btn[i].οnclick=(function(){
var temp=i;
return function(){
console.log(temp)
}
})()
}
解决方法六:
将下标添加为绑定函数的属性<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
(btn[i].οnclick=function(){
console.log(arguments.callee.i);
}).i=i;
}
解决方法七:
通过new使用Function的构造函数创建Function实例实现,由于传入的函数体的内容是字符串故Function得到的是一个字符串拷贝,而没有得到i的引用(这里先获取i.toString()然后与前后字符串拼接成一个新的的字符串,Funciton对其进行反向解析成JS代码)
<span style="white-space:pre"> </span>for(var i=0,len=btn.length;i<len;i++){
btn[i].οnclick=new Function("console.log("+i+");")
}
感谢
Tomson的解决方案点击打开链接