关于javascript:变量提升

Variable hoisting

1
2
3
alert(myVar1);
return false;
var myVar1;

上面的代码在ie、ff和opera中抛出错误,说明函数中必须有返回语句。但它在Safari和Chrome中起作用(显示undefined)。

以上代码是在全局范围内编写的。在所有功能之外。

有什么理由吗?


在javascript中,变量被移动到脚本顶部,然后运行。所以当你跑步的时候

1
2
3
var myVar1;
alert(myVar1);
return false;

这是因为JavaScript没有真正意义上的词汇范围。这就是为什么它被认为是最好的做法,把所有变量都声明在区域的顶部,它们将被用来防止提升引起问题。杰斯林特会为此抱怨的。

这篇文章很好地解释了这一点:http://www.adequatelygood.com/2010/2/javascript-scoping-and-lifting

返回无效。如果你想做一个真正的起重例子(取自上面的链接),做

1
2
3
4
5
6
7
8
var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo);
}
bar();

这将警告10

评论后编辑

下面是我的理解,我已经在某个地方读过,但找不到我读到的所有资料来源,所以我愿意改正。

由于Javascript JIT的不同,这将发出警报。tracemonkey(http://ejohn.org/blog/tracemonkey/)我相信会使用javascript,快速进行静态分析,然后执行jit,然后尝试运行它。如果失败了,那么显然没有任何效果。

V8不进行静态分析,而是移动到JIT,然后运行这样的东西。它更像Python。如果在开发人员控制台(在Windows中为ctrl+shift+j)中运行chrome脚本,它将抛出一个错误,但也会运行以向您发出警报。


有时会用一种可能给人错误印象的方式解释提升,即变量和函数被javascript引擎提升,就好像它们被物理移动到了顶部,这实际上并不正确,如下面的代码所示:

1
2
console.log(a);
var a = 'Hello World!';

我们在控制台上看到的是undefined,而不是'Hello World',所以我们得到了以下代码的行为

1
2
3
var a;
console.log(a);
a = 'Hello World!';

不是的行为

1
2
var a = 'Hello World!';
console.log(a);

您可能会从变量和函数声明移到top语句中得到印象。

但JavaScript实际上并没有将代码移动到任何地方。您需要了解JavaScript中的执行上下文。它有两个阶段:创建阶段和执行阶段。在创建阶段,为这些变量和函数创建内存空间,人们似乎将这一步与提升混淆。实际上,javascript不会将代码移动到任何地方,发生的情况是,javascript已经为所有代码(即变量和函数)创建了内存空间,函数可以完全放在内存中,但在变量的情况下,分配是在执行上下文的执行阶段处理的。因此,当您执行var a = 'Hello World!'时,javascript引擎知道a的值,当它在执行上下文的执行阶段开始执行它时,它将放置一个未定义的占位符,并且所有变量最初都在javascript中设置为未定义。因此,依靠起重作业,看不清是不好的。因此,最好在代码顶部声明变量和函数。


ECMA-262第3版第12.9节(第75页)规定:

An ECMAScript program is considered syntactically incorrect if it contains a return statement that is not within a FunctionBody.

也就是说,函数外部的return是语法错误。如果出现语法错误,则不运行任何代码。想想你的例子,就好像你写过:

1
2
3
alert(myVar1);
return false;
syntax error))))))))))))))))));

此外,第16节(第157页)规定:

An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore
report it early:

  • Improper uses of return, break, and continue.

火狐的引擎等。(即那些允许在全局范围内使用return的javascript实现)可能是一致的,假设以下条款(在同一节中)允许在全局范围内使用return的实现定义:

An implementation shall report all errors as specified, except for the following:

  • An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError).

此代码毫无意义:

  • var myVar1将永远不会运行。
  • return false;不会返回任何东西,因为您不在函数中

opera、ie和ff抛出错误是正确的,因为此代码实际上是无效的,因为除非在函数中,否则无法返回。

如果它在Safari和Chrome中工作,那一定是因为他们使用的javascript引擎已经准备好处理错误代码了。我猜他们会看到"EDOCX1"(2),然后丢弃或替换为某种break

有关函数的详细信息:http://www.w3schools.com/js/js_functions.asp


这是一个javascript提升的事情,简单地说,我们正在尝试打印变量的值,它不包含任何值。

javascript将上述代码呈现为:

1
2
3
var myVar1
alert (myVar1)
return false

为了进一步说明,我参考了链接javascript提升:http://www.ufthelp.com/2014/11/javascript-lifting.html