闭包

152 阅读3分钟

闭包

闭包的概念各有各的说法,平时人家问闭包是什么,大概多数人都是说在函数中返回函数、函数外面能访问到里面的变量,这些显而易见的现象,或者把一些长篇大论搬出来。简单来说,就是外部访问内部变量,而且内部临时开辟的内存空间不会被垃圾回收。查找值的时候沿着作用域链查找,找到则停止。 对于js各种库,是一个庞大的IIFE包裹着,如果他被垃圾回收了,我们肯定不能利用了。而我们实际上就是能利用他,就是因为他暴露了接口,使得全局环境保持对IIFE内部的函数和变量的引用,我们才得以利用。

  • 原文链接

  • 各类书籍解释

    • 《权威指南》:函数对象通过作用域链相互关联起来,函数内部变量都可以保持在函数的作用域中,有权访问另一个函数作用域中的变量
    • 《忍者秘籍》:一个函数创建时允许自身访问并操作该自身函数以外的变量所创建的作用域
    • 《你不知道的js》:是基于词法的作用域书写代码时所产生的结果,当函数记住并访问所在的词法作用域,闭包就产生了 闭包的产生,会导致内存泄漏。 前面已经说到,js具有垃圾回收机制,如果发现变量被不使用将会被回收,而闭包相互引用,让他不会被回收,一直占据着一块内存,长期持有一块内存的引用,所以导致内存泄漏。

关键字

阮一峰闭包

function f1() {
  var n = 999;
  nAdd = function () { n += 1 }
  function f2() {
    alert(n);
  }
  return f2;
}

var result = f1();

result(); // 999

nAdd();

result(); // 1000

相互引用(垃圾回收)

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。 为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。 这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。