定义一个函数
<pre>
function fn(a,b,...rest){
var arr;
...
function fn2(){
引用外部函数fn的参数a,b...rest和局部变量arr
};
return fn2;
}
fn();
</pre>
当调用fn ()这个函数时,返回的是fn2()这个函数,fn()的相关参数和变量都保存在返回的函数fn2()中,这种结构就称为闭包。闭包就是函数fn2(),即能够读取其他函数内部变量的函数。
a,b...rest,arr这些局部变量在fn()这个函数外是无法被读取的,但是有时候又想要读取这些变量,怎么办呢?
在fn的内部再定义一个函数fn2(),fn2()是可以访问fn内部所有的局部变量的,在内部引用局部变量arr,将fn2()作为返回值,即可在外面调用fn的局部变量。
<pre>
function fn() {
var n = 999;
function fn2() {
console.log(n);
}
return f2;
}
var result = fn();
result(); //999
</pre>
调用fn()时,返回的并不是n的值,而是函数fn2(),因此我门要在外面将fn赋给一个函数result,利用调用result();返回的值才是n的值。返回的函数并没有立刻执行,而是直到调用了result()才执行。
另一个例子
<pre>
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15
</pre>
同样的,当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数。调用函数f
时,才真正计算求和的结果。
当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:
<pre>var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; // false
</pre>
f1()和f2()的调用结果互不影响。
于在JavaScript语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包最大的特点,就是它可以“记住”诞生的环境,比如fn2记住了它诞生的环境fn,所以从fn2可以得到fn的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
内存泄露
因为result();一直存在在内存中,而result()的存在依赖于fn,因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收,内存一直得不到释放,JS释放内存时就会漏掉这一部分,渐渐越积越多,造成内存泄露。
返回函数不要引用任何循环变量,或者后续会发生变化的变量。
网友评论