2009-12-19 68 views
6

我对var关键字遇到了一个很奇怪的问题(对我来说)。我将它缩减为一个相当小的测试用例,并发现它在Node.js(因此,V8和Chrome),Safari 4的检查器(因此,Nitro)和FireBug(显然,SpiderMonkey)中都有展示。我原本准备一份错误报告,但由于它的显示如此广泛,我将假设我完全误解了JavaScript应该如何确定范围并查找变量。JavaScript`var`关键字的混淆操作

测试用例很小,在GitHub上:http://gist.github.com/260067。第一个和第二个示例的唯一区别是包含var关键字。

这里,以及,是指具有以不同的方式相同的“问题”进行类似的测试案例:https://gist.github.com/698b977ee0de2f0ee54a

编辑:排除任何更多的答案试图解释级联范围是如何工作的,我对此非常熟悉。我的问题是,我不明白为什么下面的代码“作品”(因为它alert() S“外,”其次是“内部”,然后再“外”):

(function(){ 
    var foo = 'outer'; 
    alert("Outer `foo`: " + foo); 

    (function(){ 
    foo = 'inner'; 
    alert("Inner `foo`: " + foo); 

    var foo; 
    })(); 

    alert("Outer `foo`: " + foo); 
})(); 

var foo;发生在与foo重新分配完全无关的位置;那为什么它会以非常实质的方式影响这项任务?

+0

为什么使用eval?绝对没有理由在您发布的代码中使用eval。 – Marius 2009-12-19 13:38:38

+0

为了演示这个问题。实际执行是非常不同的;你可以在这里看到它:http://github.com/elliottcable/poopy.js/blob/new-acquire/lib/from.js#L193 – ELLIOTTCABLE 2009-12-19 13:39:21

+0

你的最后一个例子是因为1)foo ='inner';将该值赋给父函数foo,该函数可以访问它。 2)你不需要使用var来声明一个变量。 – Marius 2009-12-19 14:04:34

回答

14

问题是,与其他语言不同,JavaScript在函数的开始处创建所有变量。这意味着代码:

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     var myVar = 5; 
    } 
})(); 

中实际上是编译和解释为

(function(){ 
    var myVar; 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     myVar = 5; 
    } 
})(); 

要创建一个变量,只有它可用内部if或循环块,你必须使用let,这是一个新的JavaScript功能。我不确定有多少浏览器实现它(如果使用<script type="text/javascript;version=1.7">,则Firefox 3.5会执行此操作)。

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     let myVar = 5; 
    } 
})(); 
+0

是的,我意识到这一点,请参阅我对上面的Amnon的回应。我的困惑源于它在本地范围*中定义之前影响来自*的调用。 – ELLIOTTCABLE 2009-12-19 13:47:39

+0

是的,我终于明白了你的问题,并重写了我的答案。希望这可以帮助。 – Marius 2009-12-19 13:55:22

+0

是的,这有所帮助。在原始问题中查看我的说明。 坦率地说,我仍然不明白为什么会发生这种情况;我想我对JavaScript语言的直观把握不符合规范/实现。 无论如何,我打算将这个答案标记为'accepted'。/ = – ELLIOTTCABLE 2009-12-19 13:57:47

1

var的含义意味着将{}的赋值完成到局部变量输出而不是全局变量输出,这意味着它不起作用。

+0

是的。我明白了。我*知道基本的JavaScript。 我的问题是,*我们正在调查的调用后*它应该对'alert()'调用时'exports'是否未定义没有影响。不管后来会发生什么,在这一点上,“出口”不是*不确定的。 – ELLIOTTCABLE 2009-12-19 13:32:22

2

var exports不能像许多语言中的局部变量一样工作。它在整个函数中声明exports作为局部变量,而不是仅仅包含块(即使它出现在第一次使用后),所以具有相同名称的函数参数是隐藏的。

编辑:let关键字的工作更传统(它只声明了包含块的变量),但它并不适用于所有版本的JavaScript。

+0

因此,解释器会提前读取,并注意到变量的声明...以及本地变量范围(附加到“未定义”)中变量的定义,会覆盖变量的变量?这*非常直观。在这种情况下,翻译如何提前阅读? O.O – ELLIOTTCABLE 2009-12-19 13:38:44

+1

是的,它是违反直觉的,但它就是这样...... 关于它是如何完成的,函数在运行之前会被解析。 – Amnon 2009-12-19 13:50:53

+0

“”“在这种情况下,解释者如何提前阅读?”“” - 它在每个实例中都显示在前面。它不像一些其他语言那样是“逐行”解析/解释器,解析器在开始执行任何操作之前会读取所有脚本。 – Hejazzman 2013-04-13 01:26:44