Javascirpt闭包问题以及解决方案

来源:互联网 发布:网页排版设计软件 编辑:程序博客网 时间:2024/06/16 07:43

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].onclick=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].onclick=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].onclick=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].onclick=(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].onclick=function(){console.log(temp);}})()}



解决方法五:

与方法三和四相似

<span style="white-space:pre"></span>for(var i=0,len=btn.length;i<len;i++){btn[i].onclick=(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].onclick=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].onclick=new Function("console.log("+i+");")}
感谢Tomson的解决方案点击打开链接
0 0