JavaScript中的函数顺序

时间:2010-12-23 11:24:47

标签: javascript interpreter

我的问题是基于“Object Oriented JavaScript”一书中的例子(第81页 - 词汇范围)

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

function f1(){var a = 1; f2();}
function f2(){return a;}
f1();

...那:

  

a未定义

但是,f1如何了解f2?f2是在f1之后定义的?

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

JavaScript解释器的工作原理?

我认为,它:

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

2 个答案:

答案 0 :(得分:16)

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

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

  1. 为执行上下文创建“变量对象”。
  2. 为上下文中的每个var和函数声明创建“变量对象”上的条目(实际上,字面上,属性)(以及其他一些内容)。在您的情况下,那是f1f2。最初,属性的值为undefined
  3. 处理所有函数声明,因此:
    • f1函数已定义并分配给变量对象的属性。
    • f2函数已定义并分配给变量对象的属性。
  4. 执行f1();行,调用f1函数。
  5. f1代码引用f2,它是从变量对象获取的,因此它是我们所期望的(对f2函数的引用)。
  6. 更有趣的版本是:

    f1();
    function f1(){var a = 1; f2();}
    function f2(){return a;}
    

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

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

    var f2 = function() {
    };
    

    或者

    setTimeout(function() {
        alert("Hi there");
    }, 1000);
    

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

    f1();
    function f1(){var a = 1; f2();}
    var f2 = function(){return a;};
    

    ...失败,因为f2在调用时未定义。

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

    alert("Beginning");
    function foo() { ... }
    setTimeout(foo, 100);
    

    按此顺序发生:

    1. foo已创建(因为它是由声明定义的)。
    2. alert运行。
    3. setTimeout运行。
    4. (稍后)foo被召唤。
    5. 最后一点:虽然工作,但包含函数 name 的函数表达式在所有实现上都不能可靠地运行,并且现在必须避免:

      var f = function foo() { ... }; // <== DON'T DO THIS
      

      或者

      setTimeout(function foo() {     // <== DON'T DO THIS
      }, 1000);
      

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

      更多探索:

答案 1 :(得分:0)

您无法访问函数f1中的变量'a',因为函数f2未在f1范围内定义

如果在f1中定义f2:

function f1(){function f2(){return a;} var a = 1; f2();}
f1();

你没有任何问题