Front-end web developer——[to be a better man]
文章字体大小Font Size文章字体大小:12px, 14px
30

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 Tags: ,

respondLeave a Reply

:mrgreen: :| :twisted: :arrow: 8O :) :? 8) :evil: :D :idea: :oops: :P :roll: ;) :cry: :o :lol: :x :( :!: :?:

&| &