2008年3月20日星期四

JavaScript上的闭包(closure)

闭包这个概念随着并发、函数式编程的复兴,也热乎了起来。”跟上Java闭包(Closure)的步伐“一文中说:
Mark Jason Dominus在Perl概述中的话语作为开场:在未来的三十年中,人们将会取笑那些发明没有闭包特性的语言的人,如同他们现在正取笑那些发明没有递归这种特性的语言的人是一个道理。
  • 定义
那么这是个啥东西? Wikipedia上对closure的解释是:
In computer science, a closure is a function that is evaluated in an environment containing one or more bound variables. When called, the function can access these variables. The explicit use of closures is associated with functional programming and with languages such as ML and Lisp. Constructs such as objects in other languages can also be modeled with closures.

In some languages, a closure may occur when a function is defined within another function, and the inner function refers to local variables of the outer function. At runtime, when the outer function executes, a closure is formed, consisting of the inner function’s code and references to any variables of the outer function required by the closure.
这个说法比较抽象。还是来看看实际的例子吧。
  • 实例说明
JavaScript中,简单的说法是: In JavaScript, if you use the function keyword inside another function, you are creating a closure.(摘自Morris Johns的JavaScript Closures for Dummies, 中文翻译可看这里: 在JavaScript中,什么是闭包)。
  1. function sayHello(name) {
  2. var text = 'Hello ' + name; // local variable
  3. var sayAlert = function() { alert(text); }
  4. return sayAlert;
  5. }
  6. var say = sayHello('Bob');
  7. say();

注 意sayAlert是sayHello的一个嵌套函数,当var say = sayHello('Bob')这行执行完之后,因为say是对内部函数sayAlert的一个引用,所以这个函数对象不会被释放,而sayAlert的 执行环境(execution context)也不会被释放,一个函数与它的数据、执行环境绑在一起,这个sayHello就是一个闭包了。

这里有好几个概念: 嵌套函数,函数引用,作用域链(scope chain),执行环境。从目前看见的资料来看,闭包的构成必须有这几个要素。
  • 作用
这个东西有什么作用呢,先看如下一个例子:
  1. var f, g;
  2. function foo() {
  3. var x = 0;
  4. f = function() { return ++x; };
  5. g = function() { return --x; };
  6. x = 1;
  7. print(f()); // "2"
  8. }
  9. foo();
  10. print(g()); // "1"
  11. print(f()); // "2"
  • 两个不同功能、相互独立的函数只能通过全局变量交换数据么(这里说语言本身提供的能力,而不是平台提供的能力)? 上面例子中两个函数都操作了变量x,但x并不是全局变量,但对于其他函数也是不可见的。可见第一个作用是提供另一种手段来供两段程序交换数据,同时保护变 量安全
  • 两个闭包建立之后,只需要根据两个引用就可以调用了,这两个引用相互独立,但又是完全自包含的,——这显然是函数式编程的风格了

没有评论: