在javascript中,有许多闭包的运用。

1. 事件响应函数

var divs = document.getElementsByTagName('div');
for(var i=0; i<3; i++){
   divs[i].onclick = function(){
       alert(i);
   } 
}

此例中,假设为3个div元素添加onclick事件,我们会发现无论点击哪一个div都会输出3。这是因为我们为div绑定的onclick事件处理函数就是一个闭包,它可以访问到这个函数定义时所处作用域中的变量。并且事件响应是异步触发的,当点击某一个div时,实际上外层循环已经结束了,i的值始终为3。

要修改这个bug可以引进一个立即执行的匿名函数,将当前的i值传入:

for(var i=0; i<3; i++){
   function(i){  
     divs[i].onclick = function(){
       alert(i);
     } 
   }(i);
}

2. 封装变量

有时候我们需要用一个全局变量来存储一些在整个程序运行过程中都需要被保存下来的值,例如一组人名和Id对应。



var persons = {};
var addPerson = function (name,id){
    if(persons.hasOwnProperty(name)){
        return false;
    }
    else {
        persons[name] = id;
        return true;
    }
}

假设只有在addPerson这个函数中我们用到了persons这个变量,就没有必要将其暴露给其他的函数以防止不必要的变量冲突,但是又不能直接将其定义在函数内部,否则会随着函数执行完毕而消失。这个时候就需要用到闭包了。修改代码如下:


var addPerson = (function (){
    var persons = {};
    return function(name,id){
        if(persons.hasOwnProperty(name)){
            return false;
        }
        else {
            persons[name] = id;
            return true;
        }
    }
})();

此例中,我们将persons封装在addPerson函数内部,并且通过在一个立即执行的匿名函数内部return一个闭包函数使得addPerson被赋值的这个函数(即return的函数)可以访问到persons这个变量。

相比于直接在addPerson函数内部定义persons这个变量,我们同样通过闭包延续了变量的生存周期,使其不至于因为函数执行结束而被销毁。

参考《javascript开发实践与设计模式》。


爱生活的玛西娜
30 声望0 粉丝

(OvO)与其过分忧虑看不清的未来,不如用心享受当下的每一个可能。