【问题标题】:Why does shadowed variable evaluate to undefined when defined in outside scope?为什么阴影变量在外部范围内定义时评估为未定义?
【发布时间】:2010-12-04 10:34:00
【问题描述】:

考虑以下代码:

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

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

提前感谢您的帮助!

【问题讨论】:

    标签: javascript variables shadowing


    【解决方案1】:

    变量会受到提升的影响。这意味着无论变量放在函数中的什么位置,它都会被移动到定义它的作用域的顶部。

    例如:

    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 处声明所有变量,以模拟将要发生的情况。

    【讨论】:

    • 多年后我不知道,也许是因为我总是在顶部声明,就像在 C 中一样。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      您现在大概可以理解为什么会出现“未定义”了。

      【讨论】:

      • 多年后更新:JavaScript 具有 let/const 的块范围,但 var 的函数范围。
      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        这是由于所谓的变量声明提升

        基本上,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 中将变量声明在函数的顶部。它可以帮助您了解代码在运行时的作用。

        【讨论】:

          【解决方案6】:

          这是一个有趣的案例。

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-08-18
            • 2013-12-06
            • 2011-09-06
            • 2016-01-13
            • 2019-10-05
            相关资源
            最近更新 更多