【CSON原创】 和大家一起分析js闭包中一个不常见的陷阱以及一个不常见的技巧...

本文探讨了JavaScript中不常见的闭包陷阱及解决方法,并提供了一种不使用闭包解决DOM元素点击事件问题的新技巧。

一个不常见的闭包陷阱:


  
var test1 = { name: ' Cson ' };
var name = ' noName ' ;
with (test1) {
function setName() {
name
= ' xiaoc ' ;

}
setName();

}

alert(test1.name);
alert(name);

我们常常在资料中看到类似这样的描述:with打开对象闭包,在对象闭包里设置属性和方法等于为该对象添加属性以及方法。按这种思路理解,上面的结果应该分别是:'xiaoc'以及'noName'.

但是实验结果是:'Cson'以及'xiaoc'。(IE chrome)'xiaoc'以及'noName' (firefox)。

分析:

其实“在with对象闭包里设置属性和方法等于为该对象添加属性以及方法”这种说法并不完美,例外的情况就是当对象闭包里嵌套函数闭包的时候,这时除了firefox还是认同上面那句话之外,ie和chrome会用另一种方法处理。

我们知道javascript的有两个运行周期:解析周期以及执行周期。当处理上面过程的时候,firefox和IE chrome采用了不同的处理方式:

firefox认为:对象闭包内的声明,作用与对象闭包本身(也就是当作test1的属性处理),因此在执行周期的时候才把setName作为test1的一个方法属性创建,所以里面处理的name也就是test1的name属性了。

但是,ie和chrome认为:对象闭包内的声明,不应该作用与对象闭包。在js的解析周期,由于with还没起作用,因此它们把setName声明解析在全局闭包域里,这时就使setName和with成为了"同级",因此setName里设置的name就成为了全局的name变量。

解决方法:

综上所述,我们只需要把对象闭包内的函数声明改成赋值,就可以避免ie和chrome在js解析周期把setName解析在全局闭包里。


  
function setName() {
name
= ' xiaoc ' ;

}

修改为


  
var setName = function () {
name
= ' xiaoc ' ;

}

这样一来,“声明”变成“赋值”,所有浏览器引擎都会在js的执行周期处理该函数。

修改后firefox ie chrome输出均为:'xiaoc'以及'noName'

一个不常见的关于闭包的技巧:

大家应该对这个闭包的经典问题不陌生了:


  
< div id ="a0" > a0 </ div >
< div id ="a1" > a1 </ div >
< div id ="a2" > a2 </ div >
< div >

  
function test2() {
for ( var i = 0 ; i < 3 ; i ++ ) {
document.getElementById(
' a ' + i).onclick = function () { alert(i); }
}
}
test2();

结果会是a0 a1 a2三个元素点击后alert的值均为3,因为闭包使它们使用了同一个i的值。

经典的解决方法是: 


  
function test2() {
for ( var i = 0 ; i < 3 ; i ++ ) {
(
function () {
var j = i;
document.getElementById(
' a ' + i).onclick = function () { alert(j); }
})();
}
}
test2();

但是这样带来了个问题,只有外部的dom元素不解除引用,闭包使整个作用域链上的变量对象被保存在内存,代来了性能上的损耗,有没有更好的方法,不使用闭包解决该问题呢?



一个更好的方法如下: 


  
function test2() {
for ( var i = 0 ; i < 3 ; i ++ ) {

(document.getElementById(
' a ' + i).onclick = function () { alert(arguments.callee.j); }).j = i;

}
}
test2();

很巧妙地通过为function设置自定义属性的方法,不用闭包,就完美解决了问题。



参考书籍:《javascript高级程序设计》《javascript语言精髓与编程实践》

欢迎转载,请标明出处:http://www.cnblogs.com/Cson/archive/2011/03/31/2001631.html

转载于:https://www.cnblogs.com/Cson/archive/2011/03/31/2001631.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值