一、前言
在学习了作用域之后,我们知道函数的AO不一定会被释放,那么利用这个特性,闭包(closure)应运而生。
二、闭包原理
函数嵌套函数,函数的AO通过作用域链相互连接起来,使得函数体内的变量都可以保存在函数的AO中,于是外部环境就能利用函数作用域内的变量,这样的特性称为“闭包”。
我们看一下代码:
function outer() { var scope = 'outer'; function inner() { return scope; } return inner;}var fn = outer();console.log(fn()); // 'outer'复制代码
解析:在inner的作用域链中拷贝着其父级函数outer的作用域链,因此当函数outer执行完成之后,抛出的函数inner的作用域链中依然有outer的作用域链,产生一个闭包,这样就可以在全局环境下使用outer中的变量了。
三、闭包的应用
1. 实现公有变量
// 一个累加器function add() { var count = 0; function addAction() { count++; console.log(count); } return addAction;}var myAdd = add();myAdd(); // 1myAdd(); // 2myAdd(); // 3复制代码
2. 缓存存储结构
function add2() { var count2 = 0; function addAction2() { count2++; return count2; } function clearAction() { count2 = 0; return count2; } return [addAction2, clearAction];}var myAdd2 = add2();console.log(myAdd2[0]()); // 1console.log(myAdd2[0]()); // 2console.log(myAdd2[0]()); // 3console.log(myAdd2[0]()); // 4// 清除一下console.log(myAdd2[1]()); // 0console.log(myAdd2[0]()); // 1console.log(myAdd2[0]()); // 2console.log(myAdd2[0]()); // 3复制代码
3. 封装功能(实现属性的私有化,避免变量公有的污染)
function counter() { var count3 = 0; var adder = { addAction3: function() { count3++; console.log(count3); }, clearAction: function() { count3 = 0; console.log(count3); } } return adder;}var myCounter = counter();myCounter.addAction3(); // 1myCounter.addAction3(); // 2myCounter.addAction3(); // 3myCounter.clearAction(); // 0myCounter.addAction3(); // 1myCounter.addAction3(); // 2复制代码
四、闭包的危险
1. 造成原有的AO不释放,产生内存泄漏(memory leak),影响内存消耗,进而影响性能。
2. 如果公有变量,那么是有可能会污染全局变量的。