JavaScript的闭包
一、前言
在学习了作用域之后,我们知道函数的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(); // 1
myAdd(); // 2
myAdd(); // 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]()); // 1
console.log(myAdd2[0]()); // 2
console.log(myAdd2[0]()); // 3
console.log(myAdd2[0]()); // 4
// 清除一下
console.log(myAdd2[1]()); // 0
console.log(myAdd2[0]()); // 1
console.log(myAdd2[0]()); // 2
console.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(); // 1
myCounter.addAction3(); // 2
myCounter.addAction3(); // 3
myCounter.clearAction(); // 0
myCounter.addAction3(); // 1
myCounter.addAction3(); // 2
四、闭包的危险
1. 造成原有的AO不释放,产生内存泄漏(memory leak),影响内存消耗,进而影响性能。
2. 如果公有变量,那么是有可能会污染全局变量的。