何为闭包?
引用维基上面的说法,闭包是词法闭包的简称,就是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
下面就自己熟悉的语言都来一种闭包。
C#:
1 var x = 1; 2 Action action = () => 3 { 4 var y = 2; 5 var result = x + y; 6 Console.Out.WriteLine("result = {0}", result); 7 }; 8 action();
在action()执行的时候就引用了外界的变量,形成了闭包。仔细观察action的定义,你会发现它使用了“x”变量。这是变量是被action“捕获”或“携带”的,自动被添加到了action的运行环境中了。当你在debug的时候,观察“action”时,会发现很有趣的事情。我们可以看到,C#编译器为我们创建了一个Target类,里面封装了x变量,如下图所示:
Python:
1 def line_conf(): 2 b = 15 3 def line(x): 4 return 2*x+b 5 return line # return a function object 6 7 b = 5 8 my_line = line_conf() 9 print(my_line(5))
在上面的代码中,返回的line函数携带了外界变量b,也就构成了最简单的闭包。在上面的代码中,最终会打印出25,而不是15,这是为什么呢?这是因为line在做为函数返回的时候,line中已经包括b的取值,也就是说,line所参照的b值是函数对象定义时可供参考的b值,而不是使用时的b值。
在python中,环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:
1 print(my_line.__closure__) 2 print(my_line.__closure__[0].cell_contents)
javascript:
javascript跟python有相同之处,因为在它们当中,函数都是做为一等公民而存在。此处就不多说了,可以参考Mgen写的这篇文章,另外在这文章中,也例举了c#跟javascript的不同。
objective-c:
在苹果的开发语言中,block就是一个明显的例子,可以自行参考,不再啰嗦。