Please enable Javascript to view the contents

什么是闭包?

 ·  ☕ 3 分钟

文章内容

  • 《JavaScript ES6 函数式编程入门经典》4.1理解闭包
  • 《JavaScript高级程序设计(第3版)
  • 《代码之髓 编程语言核心概念》
  • 闭包 - JavaScript | MDN

《JavaScript ES6 函数式编程入门经典》4.1理解闭包:

简言之,闭包是一个内部函数。那么什么是内部函数呢?它是在另一个函数内部的函数。比如:

function outer() {
	function inner() {
		// body...
	}
}

这就是闭包,函数inner称为闭包函数。闭包函数如此强大的原因在于它对作用域链的访问。

从技术上讲,闭包有3个可访问的作用域:

  1. 在它自身声明之内声明的变量
  2. 对全局变量的访问
  3. 对外部函数变量的访问,该属性使闭包变得非常强大。

《JavaScript高级程序设计(第3版) [Professional JavaScript for Web Developers 3rd Edition] 》

7.2 闭包

有不少开发人员总是搞不清匿名函数和闭包这两个概念,因此经常混用。闭包是指有权访问另一个函数作用域的函数。创建闭包的常见方式,就是在一个函数内,创建另一个函数。


《代码之髓 编程语言核心概念

代码这髓 第11章 对象与类 11.5

什么是闭包

说到闭包( closure)这个概念,想必很多人一时也说不出究竟何为闭包。它是创建具有对象性质的事物的一种技术。

很多语言都支持定义带有某种状态的函数。比如,可以定义像计数器一样每调用一次显示的数字加1的函数。我们用 JavaScript语言来实现一下。

function makeCounter(){
var count = 0
function push(){
count++;
console. log(count);
}
return push;
}

c = makeCounter()

c() // -> 1
c() // -> 2
c() // -> 3

这段代码中,函数 makeCounter中定义了变量 count和函数push,并返回函数push。然后,通过调用函数 makeCounter将返回值赋给变量c,然后调用它三次。每调用一次,显示的值就加1.这是怎么做到的呢?函数 make Counter首先创建了一张名字和值的对照表,把变量 count的值设为0.然后定义了函数push,并将其返回。函数push将其被定义时的对照表一同带出 makeCounter函数。随后,每当被调用时,函数push在被定义时的对照表的值就加1。

事实上,并没有所谓闭包的特殊的语法结构。如果有一种语言,它可以在函数中定义函数,有允许嵌套的静态作用域,并且可以把函数作为返回值传递给变量,那么它只要通过函数的嵌套就可以实现带有某种状态的函数

为什么叫做闭包

看到闭包这个名字,总有一种什么东西被严实地包裹起来了的感觉。为什么会叫做闭包呢?某 Standard ML的教材上做了如下解释。

为什么把这称为闭包?一个包含了自由变量的开放表达式,它和该自由变量的约束环境组合在一起后,实现了一种封闭的状态。

-— Ake Wikstrom, Functional programming using standard ML, Prentice-Hall, 1987.

拿上面一段代码来讲,函数push使用了变量 count,然而该变量并不是在函数push中定义的。这种变量被称为自由变量。函数push就是一个包含了自由变量的开放函数。而函数 makeCounter的对照表中为0的值和为 count的名字结合在了一起。这种给值绑定一个名字的操作叫做(名字)约束。

这样开放函数push和 makeCounter的对照表组合配套之后,无需在这以外的作用域中寻找变量的定义,从而达到了某种完备的状态。通过这样表现出一种封闭的属性。


闭包(MDN)

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

闭包 - JavaScript | MDN

分享

码中人
作者
码中人
Web Developer