Javascirpt闭包问题以及解决方案

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的解决方案点击打开链接
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值