问题引入
在一些编程语言中,函数嵌套使用时,存在这样一种情况:外层函数的生命周期已经结束,而内层函数要访问外层函数中的变量。如果没有函数闭包的支持,这将会存在问题。
以Scala语言为例,试考虑下面这种情况:
object Closure {
def main(args: Array[String]): Unit = {
def fun_outer(x: Int): Int => Int = {
def fun_inner(y: Int): Int = x + y
fun_inner
}
println(fun_outer(1)(2))
}
}
分析:两个函数嵌套使用,外部函数将内部函数作为返回值,内部函数的函数体内引用了外部函数的参数x
- 执行到
fun_outer(1)
时,1
赋值给外部形参x
上fun_outer
将fun_inner
的引用(内存地址)返回fun_outer
执行结束,x
的作用域结束,销毁- 回到主程序后,继续调用
fun_outer(1)(2)
,可以理解为调用fun_inner(2)
- 此时程序执行
x + y
时,y
的值由参数2
提供,但是x
的值已经销毁,问题由此出现
那么,如何解决这个问题呢?那就需要闭包的支持了。
什么是闭包
MDN给出的闭包的定义:
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。
如果用一个公式来概括,闭包 = 函数 + 引用环境
结合前面的例子分析:fun_inner
由于引用了fun_outer
中的局部变量x,所以x
和fun_inner
共同组成了一个闭包。闭包存储于堆中,即使fun_outer
的栈指针已经释放,但闭包的环境仍然保留下来,从而解决了作用域问题。
总结
- 闭包是函数及其引用环境的组合。
- 闭包突破了函数作用域的限制,解决了函数内部访问函数外部作用域的情况。
- 闭包存储于堆中,若滥用且不及时释放空间,可能导致内存溢出。在JVM中,闭包的释放依赖于GC垃圾回收机制。
希望这篇文章让你有所收获,如有错误也欢迎指正!