Javascript 的闭包

261 阅读2分钟

1. 闭包的概念

据我们所知,局部变量在函数退出之后就不占据内存空间,但存在一种特殊的函数,能使局部变量在函数退出之后继续占据内存,为外部函数所调用,这个特殊的函数就是闭包。那么闭包是怎么做到将局部函数一直占据内存的呢?看看下面的例子。

function a(){
    var Aitem=2;//定义局部变量item
    function b() { //定义内部函数b()
        alert(Aitem);
    }
    b();
}
a();//结果是2

2. 闭包的机理

从上可以看出内部函数可以读取外部函数的局部变量。此时的内部函数的作用域仅限于外部函数a(),只有通过调用外部函数a()才可以运行内部函数b()。当外部函数执行结束,内部函数的内存也将清除。但是如果我们将内部函数赋给一个全局变量,那么内部函数将从局部变量转化成全局变量。即使外部函数退出了,作为全局变量的内部函数也将保存在内存中。那么如何让内部函数成为全局变量呢?

function a(x){
    var Aitem=2;//定义局部变量item
    return function b(y) { //a函数结果返回一个b函数
        alert(x+y+(++Aitem));
    }
}
var closure=a(1);//将a(1)return的结果b()赋给全局变量,closure=b(y){ alert(1+y+(++Aitem))}
closure(1);//弹出5;closure(1)=b(y){ alert(1+1+(++2))}
closure(1);//弹出6;closure(1)=b(y){ alert(1+1+(++3))}

上例中的closure()函数即闭包。第一次closure(1)中Aitem=2,第二次closure(1)中Aitem=3,可以看出item这个局部变量在a()退出以后并没有被清除,而是像一个全局变量一样一直保存在内存中。这就是闭包的神奇所在。closure()闭包依赖于b(y),而b(y)又是a(x)的局部函数,故closure()闭包可以实时访问a(x)的局部变量。如果没有将内部函数装化成全局变量的话,就形不成闭包,请看下面的例子:

function a(x){
    var Aitem=2;//定义局部变量item
    function b(y) { //定义局部函数b
        alert(x+y+(++Aitem));
    }
     b(1);//在a()内部运行b(1);即alert(x+1+(++2))
}
a(1);//弹出5;即alert(1+1+(++2))

上例没有将局部函数b()赋给全局变量,在a(1)运行以后b()就不复存在,Aitem也无从获取。


3. 总结

闭包是可以读取其他函数内部变量的函数,是外部函数和内部函数的一座桥梁。

闭包拥有两个作用:

  • 使局部变量keep alive
  • 读取其他函数的局部变量

闭包的缺点:

  • 常驻内存,造成内存的浪费