为什么在外部作用域中定义时,阴影变量会被评估为未定义?

时间:2009-10-06 21:57:20

标签: javascript variables shadowing

考虑以下代码:

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

此代码的输出是警告框显示“外部”消息 范围“。但是,如果我稍微修改代码为:

<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> 

警告框显示消息“ undefined ”。我本可以有 如果在两种情况下都显示“未定义”,则理解逻辑。但是,那 没有发生。它仅在第二种情况下显示“未定义”。这是为什么?

提前感谢您的帮助!

6 个答案:

答案 0 :(得分:20)

变量受提升的约束。这意味着无论变量放在函数中的哪个位置,它都会移动到定义它的作用域的顶部。

例如:

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所具有的仅功能范围,建议在top of the function声明所有变量,使其类似于将要发生的事情。

答案 1 :(得分:12)

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

Javascript具有功能级别范围,因此在第二种情况下,它正在访问函数范围变量“outside_scope”,但在警报框时尚未初始化。所以它显示未定义。

答案 2 :(得分:5)

JavaScript具有功能范围,而不是块范围。

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

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

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

你现在可以理解为什么你会“未定义”。

答案 3 :(得分:4)

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

但是,直到警报之后才会发生实际分配,因此“未定义”。

答案 4 :(得分:1)

这是一个有趣的案例。

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

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

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

答案 5 :(得分:1)

这是由于提升变量声明

基本上,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()。我写了一篇关于这个here的深度博客文章。我希望这有助于您了解代码中发生的情况。

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