JavaScript 中的吊装顺序

Order of hoisting in JavaScript

function g () {
    var x;
    function y () {};
    var z;
}

我想知道上面的代码在挂起时到底变成了什么顺序。

理论 1: vars 和 functions 之间的顺序保持原样:

function g () {
    var x;
    function y () {};
    var z;
}

理论 2: vars 在 functions 之前:

function g () {
    var x;
    var z;
    function y () {};
}

理论 3: functions 在 vars 之前:

function g () {
    function y () {};
    var x;
    var z;
}

哪个理论是正确的?

首先提升函数,然后是变量声明,根据 ECMAScript 5, section 10.5 指定提升如何发生:

我们首先进行第 5 步处理函数声明:

For each FunctionDeclaration f in code, in source text order do...

然后第 8 步处理 var 声明:

For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do...

因此,函数的优先级高于 var 语句,因为后面的 var 语句不能覆盖先前处理的函数声明。 (子步骤 8c 强制执行条件 "If varAlreadyDeclared is false, then [continue...]",因此现存的变量绑定不会被覆盖。)

您还可以see this experimentally:

function f(){}
var f;
console.log(f);

var g;
function g(){}
console.log(g);

两个 log 调用都显示函数,而不是 undefined 值。

虽然 order 由规范确定,但正如已接受的答案所指出的那样,该顺序实际上并不那么重要。

  • var 声明被提升,但不是它们的初始化(如果有的话)。如果名称已被 function 或其他 var 声明采用,则 var 声明无效。
  • function 定义被提升——不仅声明名称,而且声明它们的值,即函数。

所以下面两段代码:

(function () {
    console.log(typeof a);
    var a = 1;
    function a() { }
})();

和:

(function () {
    console.log(typeof a);
    function a() { }
    var a = 1;
})();

... 转换为:

(function () {
    function a() { }
    var a;
    console.log(typeof a);
    a = 1;
})();

分别为:

(function () {
    var a;
    function a() { }
    console.log(typeof a);
    a = 1;
})();

后两者其实是一回事。如果引擎首先处理提升的 var 声明,那么 a 首先是 undefined 但随后立即被覆盖为函数。另一方面,如果先处理 function 定义,则 var 声明无效。在这两种情况下,结果是相同的。