转自 RednaxelaFX 博客评论

我不理解你不理解的是什么……闭包的定义很好理解撒。要点有俩:

  1. 一个含有自由变量函数
  2. 这些自由变量所在的环境

外部环境持有内部函数所使用的自由变量,对内部函数形成“闭包”,就这样…… 简单但不严格的说,一个函数的“自由变量”就是既不是参数也不是局部变量的变量。

一个纯粹(无副作用)的函数如果不含有自由变量,那么每次用相同的参数调用后的得到的结果肯定是一样的。但如果一个函数含有自由变量,那么调用返回的结果不但依赖于参数的值,还依赖于自由变量的值。因此一个含有自由变量的函数要正确执行,必须保证其所依赖的外围环境的存在。

基于类的面向对象程序语言中有一种情况,就是方法是用的自由变量是来自其所在的类的实例的。像这样:

1
2
3
4
class Foo {  
private int x;
int AddWith( int y ) { return x + y; }
}

这样的AddWith()有一个参数y和一个自由变量x,其返回的值既依赖于参数的值也依赖于自由变量的值。为了让AddWith()正确工作,它必须依附于Foo的一个实例,不然就得不到x的值了(称为:“变量i未与值相绑定”)。很好理解对吧。不过面向对象的语言里一般不把类称为闭包,没为什么,就是种习惯。
当然严格来说方法所捕获的自由变量不是i,而是this;x是通过this来访问到的,完整写出应该是this.x

如果这个“外围环境”来自一个外围函数,并且内部函数可以作为返回值返回,那么外围函数的局部环境就不能在调用结束时就撤销。也就是说不能在栈上分配空间。

1
2
3
4
5
function AddWith(x) {  
return function(y) {
return x + y
}
}

这样的内部函数有一个参数y和一个自由变量x。x在外围函数AddWith()里是一个参数,也就是一个“已绑定了值的变量”(bound variable)。AddWith()的局部作用域中含有内部函数所使用的自由变量,对内部函数形成闭包。为了让返回出去的内部函数能正常工作,这个内部函数必须依附于一个能提供x的值的环境,也就是AddWith()提供的闭包。这样我们就能够:

1
2
var addFive = AddWith(5)  
var seven = addFive(2) // 2+5=7

全局变量是一种特殊的自由变量。