2011-04-21 61 views
6

我看到此Javascript测验这里:http://www.netfxharmonics.com/2008/01/NetFX-Harmonics-JavaScript-Quiz为什么这个闭包范围变量会失去它的价值?

,我无法弄清楚这个问题:

(function(){ 
    var a = 1; 
    var b = 2; 

    (function() { a = b; var b; })(); 

    console.log('a:'+ a); // => "a:undefined" 
    console.log('b:'+ b); // => "b:2" 
})() 

但是,如果从内部函数删除var b;声明,然后a == 2如你所愿。

这是怎么发生的?

(你可以用它在这里玩:http://jsfiddle.net/gnhMZ/

回答

8

它的发生,因为这样的功能:

(function() { a = b; var b; })(); 

...分配undefinedavar takes effect as of the beginning of the scope in which it's written,不是它在哪里它是在一步一步的代码。当你声明一个变量时,它的初始值是undefined。所以,上面写的更明确,但完全相同的功能,看起来是这样的:

(function() { 
    var b = undefined; 
    a = b; 
})(); 

具体而言,当执行进入执行上下文,这些事情发生:

  1. 一个幕后-scenes 变量对象为执行上下文创建,并放在作用域链(用于解析非限定引用的变量对象链)的顶部。
  2. 无论var语句的位置如何,都会在该上下文中声明的每个var的变量对象上创建属性。每个变量的初始值是undefined。此时不处理初始化程序。
  3. 无论函数声明的位置如何,上下文中声明的每个函数(包含函数声明,而不是函数表达式)的变量对象都会创建属性。
  4. 处理函数声明并将结果分配给这些函数的属性。
  5. 执行过程继续执行上下文中的第一行代码。当遇到带有初始值设定项的var语句时,它将作为简单的赋值语句处理。

变量对象顺便说一句,也是使闭包工作的东西。 More here,但基本上,当创建一个函数时,它会在该点的作用域链中持续引用所有变量对象。这就是它用来查找它关闭的变量。这一点很重要,因为闭包不仅持久地引用它实际使用的变量,而且包含所定义范围内的所有变量,无论它是否使用它们,这可能会影响这些变量的生命周期。

+0

优秀的解释。另一个清楚的例子是,如果我们把'(function(){a = b; var b = 3;})()'作为内部函数。这与'(function(){var b; a = b; b = 3;})()'是一样的,那么,对吧? – Sam 2011-04-21 15:41:17

+0

@Sam :(谢谢)完美,是的。就是这样。很好的例子。 – 2011-04-21 15:46:17

+0

Wait..then这也意味着如果你有一个'var'语句** **函数,然后返回该函数,闭包将包含该var? – Sam 2011-04-21 15:48:52

1

一个很好的解释,但简单的答案是“a”变量没有在内部函数中声明。因此,它成为超越外部范围价值的全球范围。

a =“undefined”; // global scope

var = 1; //相对于其范围