Javascript循环添加事件——闭包好可怕
A CION HAS TWO SIDES.
“一枚硬币有两个面。”
这句话通常用于说明事物有两面性。Javascript的闭包也一样。
所谓的闭包(Closure):
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包是 ECMAScript (JavaScript)最强大的特性之一,但用好闭包的前提是必须理解闭包。闭包的创建相对容易,人们甚至会在不经意间创建闭包,但这些无意创建的闭包却存在潜在的危害,尤其是在比较常见的浏览器环境下。如果想要扬长避短地使用闭包这一特性,则必须了解它们的工作机制。而闭包工作机制的实现很大程度上有赖于标识符(或者说对象属性)解析过程中作用域的角色。 (From 《理解Javascript闭包》)
问题所在:
看下面的一个循环添加鼠标经过事件的代码:
for(var i in elements){
elements[i].onmouseover=function(){alert(i+1)};
}
假设这一组elements共有6个,你会发现每点击一下,结果总是6。不信你试试。
(有人说这会使IE内存泄漏,但暂时不讨论)
一些经历(可略过):
一年前,我在用Prototype.js写代码时经常遇到此问题,虽然每每总是非常困惑,但还好,Prototype.js有个bind()函数非常好用,而且当时写的Javascript都很OO,所以就轻易的略了过此问题。
说到闭包,我也总遇到一个问题:在内部函数改变某个外部变量,结果不奏效,能读不能写?怪事。还好,Prototype.js有个bind(),还是他,太爽了。
上次同样写一个循环添加Javascript事件的脚本,当时一边写一边心有余悸:循环,每个事件必定是最后一个i !
不管它了,写把过程写出来再说……结果一运行,奇怪,成功了,没有错误!
——原来当时使用了jQuery,同样也用到了jQuery的风格,只是还用到了他的get(),index(),不过也太神奇了!
今天不用javascript库了,祼写,又是循环,又是事件,结果卡死了。
搜索到的解决方法:
很多人问过,但高手都说已经是老生常谈的问题了,不回答,我鄙视之。
有人问说,闭包嘛,说包多一层。虽然我直接用他的方法行不通,但偶也敬之。
这里的解决方法好啊,以前有高手鄙视过51JS,但谁说51JS没高手呢?
总结出来:
使用代理方法(赞!但有不足):
function delegate(fn,param,obj){
return function(){
fn.call(obj||window,param)
}
}
不过我觉得此写法有不足,用apply()会比call()全面:
function delegate(fn,params,obj){
return function(){
fn.apply(obj||window,params)
}
}
这个时候,使用时就要注意,其中一个参数是数组:
for(var i in elements){
var _mouseoverfn=function(i){alert(i+1)};
elements[i].onmouseover=delegate(_mouseoverfn,[i],elements[i]);
//有人说最后一个参数直接用mouseover转过来的this。噢,这太可怕了,这个this?是哪个的this的啊?
}
其实我觉得这也有点麻烦,正在想更好的方法。
Popularity: 70% [?]
Tags: closure, javascript
文章字体大小:
Leave a Reply