9

考虑以下代码:

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

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

在此先感谢您的帮助!

4

6 回答 6

21

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

例如:

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 具有的唯一函数作用域,建议在函数顶部声明所有变量,以模拟将要发生的情况。

于 2009-10-06T22:09:06.410 回答
12

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

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

于 2009-10-06T22:02:23.990 回答
5

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

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

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

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

你现在可能明白为什么你会得到“未定义”。

于 2009-10-06T22:07:05.807 回答
4

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

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

于 2009-10-06T22:04:32.130 回答
2

这是由于变量声明的提升

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

于 2010-05-24T12:10:03.333 回答
1

这是一个有趣的案例。

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

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

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

于 2009-10-06T22:04:50.230 回答