// 关于效率的例子 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应用场景, 而如果不使用, 就无法解决这个问题.