闭包,又见闭包。。。。?

1.闭包是指有权访问另一个函数作用域中的变量的函数。

上面这段话来自 javascript 高级程序设计 第三版 P178 。作者说闭包是一个函数,它有访问另一个函数作用域中的变量的能力。

2.函数访问它被创建时所处的上下文环境。这被称为闭包。

这段话来自 javascript 语言精粹 修订版 P38 。作者没有定义闭包为何物,只是说函数访问它被创建时的上下文环境,这种xxx(行为?过程?能力?) 被称为闭包。

3.1闭包是依赖于词法作用域编写代码而产生的结果

3.2闭包就是函数能够记住并访问它的词法作用域,即使当这个函数在它的词法作用域之外执行时

这两段话来自 You-Dont-Know-JS 作用域闭包 这一章,作者说闭包是一种结果。


闭包的一般定义

闭包是一种抽象概念,每个人对其理解不同,所以有了上面的几种解释。但大家讨论的确是同一个问题。

//step 1
function outer() {
  var a = 'hello world';
  function inner() {
    return a ;
  }
  return inner();
}
// hello world
outer();

我们发现位于 outer 函数内的 inner 函数可以访问到另一个函数 outer 的作用域中的变量 a 。完美的闭包,对,闭包就这么简单。哈哈哈哈哈,本文结束!!!


闭包的由来

其实上面那段代码并不是大家真正所说的闭包,它其实是利用了函数作用域的特点 -- 内层函数可以访问外层变量。这仅仅是闭包的一部分,闭包利用函数作用域达到了访问外层变量 a 的目的。

依据定义 1,闭包可以说在代码 step1 中已经产生了。
我们接下来看 step2:

//step 2
function outer() {
  a = 'hello world';
  function inner() {
      return a;
    }
  return inner();
}

var c = outer();
// hello world
c;

这次我们执行 outer 函数, outer() 是一个函数对象,在内部只会返回 inner 函数的结果 a ,因为 inner 函数的存在,每次执行 inner 便会对变量 a 进行引用,这会导致变量 a 的引用计数为 1 ,从而垃圾回收机制无法销毁变量 a。我们便在函数执行完毕后依然访问到了变量 a。正规的写法如 step3:

//step3
var c = (function() {
  var a = 'hello world';
  return {
    inner : function() {
      return a;
    }
  }
})();

// hello world
c.inner();

我们利用自执行匿名函数把 inner 函数保存到对象 c 上,这时 c.inner 就是 inner 函数,它可以访问到 inner 函数之外的变量 a 。变量 c.inner 引用了变量 a 的值,导致变量 a 在函数执行后依然无法被销毁 。此时一个完整的闭包实现了, js 的垃圾回收机制由于闭包的存在无法销毁变量 a。我们利用闭包,在函数外层还是访问到了 a ,保存了函数内部的细节。这就是闭包的全部。由此得来下面定义:

4.闭包是阻止垃圾回收机制在内存中销毁变量的方法,使得在创建变量的执行环境外可以访问到该变量

上面这段话来自 单页Web应用 JavaScript 从前端到后端 P49,个人认为这本书也是对闭包解释最为详尽生动的一本书。因为此书中大量使用了模块模式所以对闭包的解释十分详尽。

总结一下:闭包是由函数产生的「函数可以创建新的作用域」,当我们把它赋值给一个变量后,一个完整的闭包出现了。它阻止了 js 的垃圾回收机制对函数内部变量的回收,导致函数内部变量的引用计数一直不为 0,无法被垃圾收集器回收。所以我们常听乱用闭包可能导致内存泄漏,就是因为闭包的这个特点。

函数作用域的特性让我们可以从函数内部取得函数外部的变量,而闭包提供了一种反向的操作可能 -- 我们在函数的外部也可以取得函数内部的变量

闭包是函数外可以访问函数内变量的实现

其它:
StackOverflow 闭包是什么
闭包的用处:You-Dont-Know-JS

你可能感兴趣的:(javascript,闭包)