Javascript 为什么阴影变量在范围外定义时计算为未定义?

Javascript 为什么阴影变量在范围外定义时计算为未定义?,javascript,variables,shadowing,Javascript,Variables,Shadowing,考虑以下代码: <html><head></head> <body> <script type="text/javascript"> var outside_scope = "outside scope"; function f1() { alert(outside_scope) ; } f1(); </script> &

考虑以下代码:

<html><head></head>
<body>
    <script type="text/javascript">
        var outside_scope = "outside scope";
        function f1() {
            alert(outside_scope) ;
        }
        f1();
    </script>
</body>
</html> 

var outside_scope=“outside scope”;
函数f1(){
警报(超出范围);
}
f1();
此代码的输出是警报框显示消息“outside”(外部 范围”。但是,如果我稍微将代码修改为:

<html><head></head>
<body>
    <script type="text/javascript">
        var outside_scope = "outside scope";
        function f1() {
            alert(outside_scope) ;
            var outside_scope = "inside scope";
        }
        f1();
    </script>
</body>
</html> 

var outside_scope=“outside scope”;
函数f1(){
警报(超出范围);
var out_scope=“inside scope”;
}
f1();
警报框显示消息“未定义”。我本来可以的 如果在两种情况下都显示“未定义”,则理解逻辑。但是, 这是不可能的。它仅在第二种情况下显示“未定义”。为什么会这样


提前感谢您的帮助

在第一种情况下,您的代码正在访问全局变量“outside_scope”,该变量已初始化为“outside scope”


Javascript具有函数级作用域,因此在第二种情况下,它正在访问函数作用域变量“outside_scope”,但在出现警报框时它尚未初始化。因此它显示未定义。

在第二个示例中,局部变量存在于整个函数范围内。在警报之后定义它并不重要,它存在于整个函数中


然而,实际的赋值直到警报之后才发生,因此“未定义”。

这是一个有趣的例子

在第一个示例中,您定义了一个“全局”变量。它具有全局作用域,因此可以在执行的任何函数/对象中访问

在第二个示例中,您使用函数范围变量“阻止”了全局变量,但由于在发出警报时它尚未初始化,因此返回“未定义”


我同意这不是最直观的怪癖,但它确实有意义。

JavaScript有函数作用域,而不是块作用域

在第二种情况下,extern_scope的声明被提升到函数的顶部(但赋值不是)

这是一个很好的例子,说明了如果将所有变量声明放在函数顶部,JavaScript代码更容易阅读的原因。您的第二个示例相当于:

function f1() {
    var outside_scope;
    alert(outside_scope);
    outside_scope = "inside scope";
}

现在,您可能理解了为什么会出现“未定义”的情况。

变量受约束。这意味着,无论变量放置在函数中的什么位置,它都会移动到定义它的范围的顶部

例如:

var outside_scope = "outside scope";
function f1() {
    alert(outside_scope) ;
    var outside_scope = "inside scope";
}
f1();
被解释为:

var outside_scope = "outside scope";
function f1() {
    var outside_scope; // is undefined
    alert(outside_scope) ;
    outside_scope = "inside scope";
}
f1();

正因为如此,而且JavaScript所具有的函数唯一作用域,建议在声明时声明所有变量,以类似将发生的情况。

这是由于一种称为提升变量声明的方法

基本上,JavaScript将变量声明一分为二,保留执行声明的赋值,并将实际声明提升到函数的顶部

var f1 = function ()  {
   // some code
   var counter = 0;
   // some more code
}

var f2 = function () {
   var counter; // initialized with undefined
   // some code
   counter = 0;
   // some more code
}
在运行时,
f1()
被转换为
f2()
。我为此写了一篇深入的博客文章。我希望这能帮助您理解代码中发生了什么


这也是原因,建议在JavaScript中在函数顶部声明变量。它可以帮助您理解代码在运行时的作用。

多年后,我不知道这一点,可能是因为我总是在顶部声明,就像在C中一样。