一个不常见的闭包陷阱:
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解析在全局闭包里。
name = ' xiaoc ' ;
}
修改为
name = ' xiaoc ' ;
}
这样一来,“声明”变成“赋值”,所有浏览器引擎都会在js的执行周期处理该函数。
修改后firefox ie chrome输出均为:'xiaoc'以及'noName'
一个不常见的关于闭包的技巧:
大家应该对这个闭包的经典问题不陌生了:
< div id ="a1" > a1 </ div >
< div id ="a2" > a2 </ div >
< div >
for ( var i = 0 ; i < 3 ; i ++ ) {
document.getElementById( ' a ' + i).onclick = function () { alert(i); }
}
}
test2();
结果会是a0 a1 a2三个元素点击后alert的值均为3,因为闭包使它们使用了同一个i的值。
经典的解决方法是:
for ( var i = 0 ; i < 3 ; i ++ ) {
( function () {
var j = i;
document.getElementById( ' a ' + i).onclick = function () { alert(j); }
})();
}
}
test2();
但是这样带来了个问题,只有外部的dom元素不解除引用,闭包使整个作用域链上的变量对象被保存在内存,代来了性能上的损耗,有没有更好的方法,不使用闭包解决该问题呢?
一个更好的方法如下:
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