简单理解JS中的闭包

定义一个函数
<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释放内存时就会漏掉这一部分,渐渐越积越多,造成内存泄露。

返回函数不要引用任何循环变量,或者后续会发生变化的变量。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 函数声明和函数表达式有什么区别 (*)解析器会率先读取函数声明,并使其在执行任何代码之前可以访问;函数表达式则必须...
    coolheadedY阅读 402评论 0 1
  • 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量...
    zock阅读 1,086评论 2 6
  • 郭芳艳 焦点网络五期 坚持原创分享第81天 2017.8.11 假期里总是感觉比上班还忙,一个人在家...
    冰山蓝鹰阅读 93评论 0 0
  • 小朋友们,你们知道吗?中国五岳名山有哪些?有东岳泰山,南岳衡山,北岳恒山,西岳华山,中岳嵩山。你们知道...
    fdeceb686cba阅读 596评论 0 0
  • 今天在做一个menu的时候,需要改动item的高度和字体大小颜色。搜索了一下很多方法都不管用,最后是结合了 sta...
    seven_Android阅读 8,144评论 4 3