重新声明JavaScript变量

Lev*_*lho 6 javascript scope function

在以下代码中:

var greeting = "hi";

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

    alert(greeting);
}

changeGreeting();?
Run Code Online (Sandbox Code Playgroud)

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

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

    alert(greeting);
}
Run Code Online (Sandbox Code Playgroud)

......我按预期"打招呼".

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

Ama*_*dan 27

JavaScript变量具有函数范围.因此,var greeting函数内部的存在将声明一个局部greeting变量,该变量在if条件提及时将是未定义的:全局变量在函数内部不可见,被本地变量所掩盖.因此,if不会发生,赋值hello不会发生,变量仍未定义.

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


Eli*_*gem 6

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

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

通过省略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
}());
Run Code Online (Sandbox Code Playgroud)