闭包的概念
MDN版:一个函数和对它周围状态的引用捆绑在一起,这样的组合就是闭包(closure)。闭包可以让内层函数中访问到其外层函数的作用域,在JS中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
简单来说,闭包就是能够读取其它函数内部变量的函数,它是将函数内部和函数外部连接起来的一座桥梁。
闭包的用途
参考阮一峰的学习Javascript闭包(Closure) - 阮一峰的网络日志 (ruanyifeng.com)
代码示例
function f1(){
var n = 999;
nPlus = function(){n += 1;}
function f2(){
alert(n);
}
return f2;
}
var result = f1();
result(); // 999
nPlus();
result(); // 1000
闭包不仅可以读取函数内部的变量,还能让这些变量的值一直保存在内存中。
这段代码中,result 实际上就是闭包 f2 函数,它一共运行了2次,第一次是999,第二次是1000,这说明 f1 中的局部变量 n 并没有在调用之后被清楚,而是保存在内存中。
导致这种情况的原因是因为,函数 f1 跟 f2 是父子关系,而函数 f2 被赋给了一个全局变量,这导致f2始终在内存中, f1 则因为是 f2 父函数的关系被保留在内存中,而不会因为在调用后被垃圾回收机制回收。
关于setter
函数f1中的nPlus = function(){n += 1;}前面没有使用var,所以nPlus是一个全局变量而不是局部变量。另外nPlus的值是一个匿名函数,这个函数本身也是一个闭包,所以nPlus相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
闭包使用的时候需要注意的两点
不要滥用闭包
闭包会使函数中的变量都被保存在内存中,因此内存的消耗很大,滥用则有可能造成网页的性能问题。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部改变父函数内部的值
如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。