黑铁时代
Programing is not only one kind of technology, but also one kind of art.

  闭包是JavaScript语言最奇怪的特性之一,闭包也经常让我们感到疑惑,但是只要弄清楚闭包产生的原理,我们就可以很好的利用它了。

 

  闭包产生的根本原因就是作用域链。我们应该知道,当某个外部作用域包含一个内部作用域的时候,内部作用域可以通过作用域链访问外部作用域的变量对象。即使外部作用域已经销毁,但只要这个内部作用域还继续被使用,那么它就可以继续访问外部作用域中的变量对象,这个特性就叫闭包了。

 

  在JavaScript只存在两种作用域:全局作用域和函数作用域。因此,产生闭包的通常情况都是在一个函数内部创建了另一个函数。当一个函数被创建的时候,就会自动创建一个内部属性引用相应的作用域链。当这个函数被执行的时候,this,arguments以及所有的变量,都会用于创建函数的活动对象,这个活动对象会放在整个作用域链的最顶端,也就是当前执行环境的作用域。外部函数的作用域放在整个作用域链的第二个位置,如果外部函数被包含在另一个外部函数的内部,那么另一个外部函数的作用域会放在整个作用域链中的第三个位置,以此类推......当然每个作用域都包含它所有的变量对象,作用域只是指向其变量对象的一个指针而已。

  下面来看个例子:

  var globalVar = 'Hello, i am the global var';

  function outFun() {

    var outVar = 'Hello, i am the out fun';

    

    return function() {

      alert( globalVar );

      alert( outVar );

    }

  }

  var outfun = outFun();

  outfun(); // 先后弹出 Hello, i am the global var 和 Hello, i am the out fun

  我们先创建了一个outFun函数,然后outFun有一个局部变量outVar,这个时候outFun有一个内部属性引用作用域连,这个作用域链的顶端是outFun的作用域,第二个位置是全局的作用域。当outFun执行的时候,outFun的内部属性this,arguments和变量outVar都会用于创建当前的活动对象,outFun的作用域就会指向这个活动对象,而全局作用域会指向一个全局的变量对象,包括global,window,outFun, outfun。当outfun在执行的时候,也会创建自己的作用域链,并初始化自己的活动对象(包括this,arguments),并将其推入到整个作用域链的最顶端。outfun执行过程中,先去查找globalVar,通过作用域链在第三个位置的全局作用域中找到了,再去查找outVar,通过作用域链在第二个位置的outFun的作用域中找到了。虽然outFun在执行完成后,其执行环境就被销毁,但是outfun始终保存着对outFun作用域中所有变量对象的引用,这些变量对象不会被销毁,依然保存在内存中,除非outfun被销毁(outfun == null)。

 

  说了这么多,其实闭包就是一个内部函数可以访问其外部函数中的所有变量对象,但是this,argument是不能通过原型链查找的,除非你将this,arguments赋值给一个局部变量进行保存。

posted on 2012-07-04 23:28  黑铁时代  阅读(140)  评论(0编辑  收藏  举报