7

在以下代码中:

var greeting = "hi";

function changeGreeting() {
    if (greeting == "hi") {
        var greeting = "hello";
    }

    alert(greeting);
}

changeGreeting();​

...greeting未定义。但是,如果我删除var并更改changeGreeting()为:

function changeGreeting() {
    if (greeting == "hi") {
        greeting = "hello";
    }

    alert(greeting);
}

...我按预期得到“你好”。

我永远不会在我的代码中重新声明这样的变量,但为什么会发生这种情况?

4

3 回答 3

27

JavaScript 变量具有函数作用域。因此,var greeting函数内部的存在将声明一个局部greeting变量,在条件中提到它时将未定义if:全局变量在函数内部将不可见,被局部变量所掩盖。因此,if不会发生,分配hello不会发生,变量仍然是未定义的。

在第二个示例中,您始终使用全局变量,它不会被局部变量所掩盖(因为,var greeting函数内部没有),并且事情按您预期的那样工作。

于 2012-11-29T12:44:58.240 回答
6

这很简单:JS 将变量声明提升到当前作用域的顶部,但是任何操作(包括赋值)都不会被提升(在同一作用域内,请参阅第二种情况说明),当然。所以你的片段被翻译成

(function()
{
    var currentSize;//undefined
    if (currentSize == 'hi')//always false
    {
        currentSize = 'hello';//assignment that will never be
    }
    alert(currentSize);//alerts undefined, of course
}());

通过省略 var,继续进行范围扫描(检查在全局范围内声明的变量)。可悲的是,这样做时,第一次使用 var 的上下文丢失了(在分支内),并且赋值也被提升了。一个隐含的全局被翻译为
谢天谢地,这不是真的。我认为是这样,因为我在控制台中测试了一些似乎证实了这一点的东西。在这种情况下@amadan 是对的:您正在使用全局变量(greeting当我发布此内容时错误地在您的代码段中调用)。我将留下下面的代码(更正它)以显示隐含的全局变量实际上是什么,希望它有助于某些人理解 JS 中的作用域/作用域扫描。

var currentSize = 'hello';
//well, actually implied globals can be deleted, so it's more like
Object.defineProperty(this,'currentSize',{value:undefined,
                                          writable:true,
                                          enumerable:true,
                                          configurable:true});
(function()
{
    if (currentSize == 'hi')//always false
    {//this still doesn't get executed
        currentSize = 'hello';//assignment that will never be
    }
    alert(currentSize);//alerts undefined
}());
于 2012-11-29T12:53:05.690 回答
-1

在您的第一个代码片段中,您正在检查全局变量,该变量不存在 -> if 条件不通过。

在 javascript 作用域上查看此内容以及如何使用变量Javascript garden - 函数作用域

于 2012-11-29T12:46:52.280 回答