白也blog - 函数
type: channel
link: http://www.baiyeovo.cn/index.php/tag/%E5%87%BD%E6%95%B0/
items: js闭包的理解(引自知乎)

js闭包的理解(引自知乎)
type: item
date: 2022-03-20T12:09:00+08:00
description: 作者：Saviio链接：https://www.zhihu.com/question/34210214/answer/94933160来源：知乎著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。闭包其实是一个很通用的概念，正如 @寸志 老师说的：「闭包是词法作用域的体现」。 而很多大家耳熟能详的语言里都支持函数作为一类对象，比如JavaScript，Ruby，Python，C#，Scala，Java8.....，而这些语言里无一例外的都提供了闭包的特性，因为闭包可以大大的增强函数的处理能力，函数可以作为一类对象的这一优点才能更好的发挥出来。那什么是闭包呢，一言以蔽之：一个持有外部环境变量的函数就是闭包。 理解闭包通常有着以下几个关键点：1.函数2.自由变量3.环境举个栗子：let a = 1let b = function(){console.log(a)}在这个例子里函数b因为捕获了外部作用域（环境）中的变量a，因此形成了闭包。 而由于变量a并不属于函数b，所以在概念里被称之为「自由变量」。再举个栗子：function a(x, y){console.log(x, y) //在这里，x和y都不是自由变量 function b(){ console.log(x, y) //但在这个内部函数b中，x和y相对于b都是自由变量，而函数a的作用域则是环境。 } //无论b最终是否会作为返回值被函数a返回，b本身都已经形成了闭包。}为了更直观的描述「捕获」这个过程，再用PHP来个栗子：function getMoney() { $rmb = 1; $func = function() use ( $rmb ) {echo $rmb;}; $func();}在这里 use 这个关键字直接对应的描述了「捕获」这一概念。在代码中，开发者需要显式的通知引擎：我需要捕获一个环境里的变量在之后的Function Block里使用。（当然，由于PHP需要手动声明，所以经常被人诟病说支持的不够自然。P.S：在一些语言里，「捕获」这一行为还有一个特点：闭包只会捕获自由变量的引用。这也是为什么大家在JS里写循环的事件绑定时，需要再额外的使用一个IIFE来包裹的原因。（用IIFE对自由变量的引用立即求值）所以其实闭包是一个比较直观的概念，不过之前有人问：如果这么解释，那和别的一些OO的语言看起来没区别啊，即使是早期的C#也可以像下面这么用，不也使用了函数作用域以外的变量吗Class A{private int x = 1; public int value() { return x; }}但实际，上面的代码是省略一部分状语的。编译器会知道，它表达的其实是如下的意思。Class B{private int x = 1; public int value() { return this.x; }}变量x其实是实例上的成员。成员函数的使用必须依附于类的实例。当然如果用闭包的设计来理解的话也可以对应的理解成 「实例是其拥有的成员函数的环境」。（不过，你看一些以闭包为特性的语言比如JS里，函数可以捕获很多层作用域之外的变量，因此也较之有着更好的表达力。大抵就是这样。