函数外面通常拿不到里面的局部变量。变通办法是:在函数里再定义一个函数,把它 return 出去。里面那个函数就是闭包。
javascript
function f1() {
var n = 999;
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999f2 在 f1 内部,能看见 f1 的局部变量;反过来不行。这是作用域链:内层能向外找,外层不能向内找。把 f2 返回到外面,就等于留了一座桥,专门用来读(或改)那批本来出不去的变量。
变量会留在内存里
javascript
function f1() {
var n = 999;
nAdd = function () {
n += 1;
};
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000result 实际是 f2。调两次,n 从 999 变成 1000,说明 f1 结束之后 n 没有被回收。f2 还被外面握着,它又依赖 f1 的环境,于是那份环境一直活着。
注意 nAdd 前面没有 var / let / const,它漏成了全局变量,本身也是闭包,相当于给 n 做了一个外部的 setter。现在更稳妥的写法是不要这样漏全局,把增减也 return 出去,或放在一个返回的对象上。
可以记:闭包能读到外层函数的局部变量,并让它们按需要活着。这也是它容易把内存咬住的原因——外面还握着内层函数,外层的变量就扔不掉。