让我们先来看一个简单的例子
function test1() {
function test2() {
var b = 2;
console.log(a);
}
var a = 1;
return test2();
}
var c = 3;
var test3 = test1();
test3();
尽管此时test1已经销毁(销毁理应a为undefined)
test1执行结束之后应该销毁掉scope chain和对应的AO,但此时test2也连着test1的AO,所以消除不掉.把test2再return给一个外部的变量test3的时候,操作test3即执行test2,能够调用已经结束的test1的AO
如上,当内部函数(test2)被返回到外部(return test2;)并保存时(var test3 = test1()😉,一定会产生闭包,闭包会产生原来的的作用域链不释放的现象(test2仍拥有test1的AO),过度的闭包可能会导致内存泄漏或加载过慢(占用内存).
function test() {
var n = 100;
function add() {
n++;
console.log(n);
}
function reduce() {
n--;
console.log(n);
}
// 返回两个函数可以用数组实现
return [add, reduce];
}
var arr = test();
arr[0]();
arr[1]();
// arr[i]刚才只是保存了函数名,调用函数不加括号,执行函数加括号
GO: {
arr: undefined,
function test() { },
}
AO: {
n: undefined,
function add() { },
function reduce() { },
}
test.[[scope]] -> 0 : test.AO
1 : GO
add.[[scope]] -> 0 : add.AO X //后面执行的时候又会生成,且1号和2号保存的也能用
1 : test.AO
2 : GO
reduce.[[scope]] -> 0 : reduce.AO X //后面执行的时候又会生成,且1号和2号保存的也能用
1 : test.AO
2 : GO
//101
//100
//实例
function breadManager(num) {
var breadNum = arguments[0] || 10;
function supply() {
breadNum += 10;
console.log(breadNum);
}
function sale() {
breadNum--;
console.log(breadNum);
}
return [supply, sale];
}
var breadManager = breadManager(50);
breadManager[0]();
breadManager[1]();
// 注意,"var breadManager = breadManager(50);"中supply()和sale()仅仅被定义而未被执行!!所以这句话不会改breadNum的值
//60
//59
//除了数组,也能用对象的方式试用闭包
function sunSched(thing) {
var sunSched = '';
var operation = {
setSched: function (thing) {
sunSched = thing;
},
showSched: function () {
console.log("My schedule on sunday is " + thing)
}
}
return operation;
}
var sunSched = sunSched('studying');
sunSched.setSched('playing');
sunSched.showSched();