javascript必知必会之closure
2009-09-21 00:00:00 来源:WEB开发网关于closure的效率
因为在closure的实际应用可能会多次去生成一个内部函数(匿名),所以存在可能的效率问题.(对象的建立,内存管理释放等).
所以,应该尽量减少内部函数的生成, 而使用函数的引用.
例如:
// 关于效率的例子
flag = false;
// 这样,每次调用Outer时会产生匿名函数的开销
function Outer(obj)
{
obj.fun = function(){
alert("I am " + this.name);
};
}
if (flag)
{
var obj = { name : "zhutao"};
Outer(obj);
obj.fun();
}
// 更好的处理方式
function Outer_better(obj)
{
obj.fun = showme; // 这样调用的只是函数的引用
}
function showme()
{
alert("I am " + this.name);
}
if (flag)
{
var obj2 = { name : "zhutao"};
Outer_better(obj2);
obj2.fun();
}
应用建议
Don't use closures unless you
really need closure semantics.
In most cases, nonnested
functions are the right way to go.
Eric Lippert, Microsoft
上面的论述是基于效率的考虑, 而 IE 4-6 在使用closure时可能会存在内存泄露的问题,参考 JavaScript Closures 中的相关部分.
而在某些场合,你可能必须要使用closure, 如 循环问题.
代码:
flag = true;
// 向body中生成一些链接,然后绑定事件
function addLink(num)
{
for(var i=0; i<num; i++)
{
var link = document.createElement('a');
link.innerHTML = "Link " + i;
link.onclick = function(){
alert(i);
};
document.body.appendChild(link);
}
} //可惜的是,当你点击每个链接时,输出的都是 Link 4
// 使用closure 可以解决这个问题
function addLink2(num)
{
for(var i=0; i<num; i++)
{
var link = document.createElement('a');
link.innerHTML = "Link" + i;
link.onclick = function(j){ //使用closure
return function(){
alert(j);
};//返回一个函数
}(i);//调用这个函数
document.body.appendChild(link);
}
}
window.onload = addLink(4);
window.onload = addLink2(4);
为什么会出现上面的这个问题?(事实在之前的的一个项目中,也遇到了相同的问题,但是当时还不懂closure, 也是一头雾水)
这是因为,对于addLink, 在退出addLink函数之前, i已经变成了4,所以无论后面的事件触发,输出的都是4.
但是后者,使用了closure.使得j引用了当前的循环中的i,所以对于每个后续触发事件,都会按照预期地得到相应的结果.
这即是一个典型的closure应用场景, 而如果不使用, 就无法解决这个问题.
结论
下面这段摘抄自 Summary of JavaScript closures :
当你在一个函数中使用另一个函数时, 会产生一个closure
当你使用eval()时, 会产生一个closure.
最好认为closure总是在函数入口处产生,并且本地变量自动添加到closure中
其它的细节可参考上面的链接.
总之, 关于closure,你必须记住以下几点:
closure就是提供了一种变量共享的机制(内部函数可以访问外部函数的变量)
注意closure可能引用的效率问题(如何避免,参见文中详述)
具体的应用场景要熟悉
上篇博文讲的是 prototype, 下篇博文预计会讲 this关键字, 欢迎大家讨论和留言.
编缉推荐阅读以下文章
- javascript必知必会之prototype
Tags:javascript closure
编辑录入:爽爽 [复制链接] [打 印]更多精彩
赞助商链接