什么是闭包?

说明

  函数是编程语言中比较基本的概念。但随着技术的发展,函数的功能被延伸,一些类似函数但又与之有别的概念诞生,如 lambda 表达式、箭头函数等等。但为了便于描述,本文也将它们称为函数,尽管普通的函数与它们不尽相同。

  闭包的概念在 JavaScript 中更常用,后来也延伸到 Java、C++ 中。

闭包

  闭包(closure)是使用了它的外部函数局部变量的函数。

  具体来讲,如果 A 是一个函数,而 B 是在 A 中定义的一个函数(表达式),且在 B 的函数体中使用了 A 的局部变量 a,那么就将函数 B 称为闭包。

  闭包 B 之所以与普通的函数有所不同,因为它将导致它所使用的外部函数的变量 a,不会在该外部函数 A 执行完时销毁。而之所以会这样,是因为如果在刚才的 A 中,将函数 B(不是 B 的返回值)传给其它不在 A 包含范围内的函数 C,那么当 A 执行完时,函数 C 想使用这个函数 B,那么将必须保证B使用的变量 a 一直存在。这并不能通过判断变量 a 是否被引用来保证变量 a 是否可以销毁。其中的缘由略复杂,这里将情景详述如下:

  【1】A 是一个函数,B 是在 A 中定义的一个函数(表达式),且在 B 的函数体中使用了 A 的局部变量 a。函数 C 是一个与 A 没有包含关系的函数,且 A 与 C 之间不存在互相调用。

  【2】A 将 B 传给了一个不在 A 包含范围内的公共存储区 R。

  【3】函数 A 执行完毕,此时函数 C 还没有开始执行。

  【4】程序去执行与函数 A、B、C 均无关的代码。

  【5】函数 C 开始执行,从公共存储区R取出并调用了函数 B,B 使用了 A 的局部变量 a。

  可以看出在过程【4】中,A 的局部变量 a 没有被任何代码块所引用,因为此时函数 A、B、C 都没有执行,没有执行就意味着函数 A、B、C 中任何局部变量都不会创建,因此 A 的局部变量 a 在过程【4】中是不会被引用的。按一般的变量回收规则,a 理应被销毁,但这将导致过程【5】引发异常。因此,一个编程语言要支持闭包,就要使用一个额外的机制来防止过程【3】与【5】之间的局部变量 a 不会被回收。

  有些场景中,闭包是一种回调函数的实现。使用嵌套太多的异步闭包会导致 回调地狱 问题。

闭包的特殊之处

闭包不仅仅是一种简化的函数而已。闭包有以下几个与普通函数没有的特性。

  1. 可传递性。

    闭包是可以当成一个对象来进行传递的,而普通的函数只能直接调用,而不能传给其它函数。

  2. 异步调用、异步反馈。

    闭包可以在闭包被传入时不马上执行,而改为在以后的某个时间中异步执行。此外,闭包在进行结果反馈时,通常也不能向普通函数一样使用返回值,而使用的是异步反馈。

  3. 可以使用外部函数的局部变量。

    一个在其它地方定义的普通函数,一定是没有权限访问其它函数的局部变量的。因为不同函数之间的执行是单独、异步的,因此无法保证使用前,这些局部变量是否则被创建,因此普通函数不能其它函数的局部变量。

    而闭包在创建的时候,外部函数肯定已经在执行了,所以局部变量的创建可以得到保障,接下来只需要考虑它的销毁问题。


【附】


闭包在一些编程语言中的限制

Java

  因为前面所说的外部函数局部变量的回收问题,所以在 Java 中,闭包使用的变量必须是“最终事实变量”,也就是只读变量。

  为什么会这样呢?因为 Java 的语法规定,所有的局部变量都是基本类型或对象引用,都存放在栈中,在当前代码块结束之后就会销毁,这个过程不受控制,自动完成的。因此,如果当闭包传给其它函数并执行时,原外部函数的局部变量已经销毁了,所以这种改值是非法的。

  但 Java 还有另外一个规定,那就是所有的对象都是匿名、由 Java 虚拟机来控制回收的。因此,当外部函数的局部变量已经销毁时,这个局部变量引用的匿名对象还没有销毁。所以,Java 允许修改一个局部变量引用的匿名对象的值,但不允许修改这个局部变量的值。

  这种说法听起来很绕。前面有言,所有的局部变量都是基本类型或对象引用。在 Java 中,修改局部对象引用变量的值指的是将这个局部变量引用其它对象或设置为 null,而不是指修改它指向的匿名对象的值。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值