JavaScript的闭包

标签:JavaScript

在某个jQuery的论坛看到有人问闭包是怎么回事,于是稍微介绍一下。

首先说下语法域和执行域这2个概念。
所谓语法域,是指定义某个程序段落时的区域,所谓执行域则是指实际调用某个程序段落时所影响的区域。
简单而言,定义了一个函数,那么这个函数内部就是它的语法域,而它能影响的程序范围就是它的执行域。

对于C++这种静态语言来说,函数的执行域一般就是其函数内部(包括参数),以及全局对象。成员函数还能访问对象自身的成员函数和变量。
而对于JavaScript这种动态语言而言,函数的执行域还包括其外层函数的执行域。(实际上大多数动态语言都可以,甚至Pascal这种静态语言也能嵌套定义函数。)

如此一来,无论外层函数是否执行结束,内层函数都能访问其执行域的变量,当然也就包括其外层函数的变量,这就是闭包的本质。
详细的定义如下:所谓闭包,是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。

下面来看个非常简单的闭包的例子:
function a(x) {
  return function () {alert(x);};
}
var b = a(5);
b(); // 弹出5
函数a返回了它内部的一个匿名函数对象,而该匿名函数又引用了函数a的变量x。
一般情况下,函数a调用完后,它的变量也就消失了。但函数b引用了a内部的匿名函数,于是获得了本应消失的变量x。(事实上是由于b引用了x,所以x不会被释放。)

而且闭包会一直保持其外层执行域的变量的引用:
function a(x) {
  function b() {alert(x);};
  ++x;
  return b;
}

var c = a(1);
c(); // 弹出2
可以看到,即使函数b已经定义完毕,更改其外层函数a的变量x后,函数b内部对x的引用也会相应改变。

实际上闭包没什么神奇的,只是单纯地因为被引用而无法回收而已。所以对于很大的对象,使用闭包也是要考虑内存的占用量的。
然而闭包也不是单纯为了好玩,在传递函数对象时,它与接收函数便形成了嵌套函数的关系,于是很可能你在不知不觉中便用到了闭包。如果没有闭包,函数式编程便成了不可能。

17条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?