理解JavaScript闭包

《高级程序设计》上,这样说:当函数内部定义了其他函数的时候,就创建了闭包。闭包有权访问包含函数内部的所有变量。

简单说一下我的理解:

由于普通的函数执行之后,资源就会被回收、内存释放,如果需要保留其内部的变量,那么我们需要建立函数的闭包。

function a(){
    var i = 0;
    function b(){
        alert(i++);
    }      
    return b;
}

var test = a();
test();

上面例子中,当函数a执行完并返回后,闭包使得JavaScript垃圾回收机制不会回收a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

由于闭包的存在使得函数a返回后,a中的变量i始终存在,这样每次执行test(),都会弹出自加1之后的i。

另外闭包也可以实现封装,在person之外无法访问其内部的变量,而通过提供闭包的形式来访问,例子如下

var person = function(){
    var name = "默认";
    return{
        "setName":function(newName){
            name = newName;
        },
        "getName":function(){
            return name;
        }
    }
}();

console.log(person.getName());
person.setName("李四");
console.log(person.getName());

闭包的另外一个重要用途是实现面向对象中的对象,传统的面向对象语言都有类的模板机制,这样不同的对象拥有独立的成员及状态,互不干涉。虽然JavaScript中没有类这样的机制,但是通过使用闭包,可以模拟出这样的机制,例子如下:

function Person(){    
    var name = "默认";         
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
};    
     
     
var john = Person();    
console.log(john.getName());    
john.setName("john");    
console.log(john.getName());    
     
var jack = Person();    
console.log(jack.getName());    
jack.setName("jack");    
console.log(jack.getName());    

以上例子中,john和jack都可以称为是Person这个类的实例,因为这两个实例对name这个成员的访问是独立的,互不影响的。

总结:

在函数内部定义子函数,这个子函数可以称为闭包,可以使用闭包来解决在函数外部如何访问函数内部变量的问题,实现父函数变量的保留。

通常如果不使用闭包,我们为了取值方便可能会将有些局部变量直接定义为全局变量,这样造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。有了函数的闭包也减少了对全局变量的使用,从而减少内存的占用。