JavaScript中的函数顺序

Ant*_*nAL 7 javascript interpreter

我的问题是基于" 面向对象的JavaScript " 一书中的例子(第81页 - 词汇范围)

所以,我从这个例子中理解......

function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
Run Code Online (Sandbox Code Playgroud)

......那:

a未定义

但是,f1如何知道在f1之后定义的f2?

这种行为引发了一个问题:

JavaScript解释器如何工作?

我认为,它:

  1. 扫描代码并简单地存储在全局环境中未分配给任何var的函数
  2. 以临时方式调用函数:当在全局环境中没有这样的函数时,然后抱怨.

T.J*_*der 16

在处理上下文中的任何逐步代码之前,在进入可执行上下文(例如,全局上下文或函数调用)时处理函数声明.

所以在你的代码中,这些事情发生了(按此顺序):

  1. 为执行上下文创建"变量对象".
  2. "变量对象"上的条目(实际上是字面上的属性)是为var上下文中的每个和函数声明创建的(还有一些其他的东西).在你的情况下,那是f1f2.最初属性具有值undefined.
  3. 处理所有函数声明,因此:
    • f1函数被定义并分配给它的属性变量对象上.
    • f2函数被定义并分配给它的属性变量对象上.
  4. f1();执行该行,调用该f1函数.
  5. f1代码是指f2,它从变量对象中获取,所以这是我们希望它是(一个参考f2函数).

更有趣的版本是:

f1();
function f1(){var a = 1; f2();}
function f2(){return a;}
Run Code Online (Sandbox Code Playgroud)

... 以与上面列出的完全相同的顺序发生,因为两个声明都是在第一行逐步代码之前处理的.

函数声明与函数表达式不同,函数表达式就像在逐步执行代码时达到的任何其他表达式一样进行评估.函数表达式是您创建函数并将其用作右侧值时的任何时间,例如,将结果分配给变量或将其传递给另一个函数.像这样:

var f2 = function() {
};
Run Code Online (Sandbox Code Playgroud)

或这个

setTimeout(function() {
    alert("Hi there");
}, 1000);
Run Code Online (Sandbox Code Playgroud)

请注意,我们将function语句的结果用作右手值(在赋值中,或通过将其传递给函数).那些在进入执行上下文时没有被预处理(例如,不在上面的步骤3),它们在代码流到达它们时被处理.这导致:

f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};
Run Code Online (Sandbox Code Playgroud)

...失败了,因为f2它被调用时是未定义的.

您可以将声明函数的值用作右手值而不将其转换为函数表达式(我们一直这样做),只要您在两个单独的语句中执行它.所以:

alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);
Run Code Online (Sandbox Code Playgroud)

这按顺序发生:

  1. foo 是创建的(因为它是由声明定义的).
  2. alert运行.
  3. setTimeout运行.
  4. (后来)foo被召唤.

最后一点:虽然它们应该工作,但是包含函数的函数表达式在所有实现上都不能可靠地工作,并且现在必须避免:

var f = function foo() { ... }; // <== DON'T DO THIS
Run Code Online (Sandbox Code Playgroud)

要么

setTimeout(function foo() {     // <== DON'T DO THIS
}, 1000);
Run Code Online (Sandbox Code Playgroud)

特别是Internet Explorer存在问题,其他实现也有不同的时间.

更多探索: