这种行为有什么解释? (什么时候创建函数?)

时间:2011-09-07 15:46:06

标签: javascript function

有问题的代码很简单:

console.log("So it begins.");
foo();
function foo() { console.log("In foo()."); }
console.log("So it ends.");

为什么foo()在定义之前执行(追溯编辑:在Chrome和Safari中)?

我对此进行了修改,在Chrome,Safari和Firefox中测试了以下代码:

javascript:foo();function foo() { alert("Oh."); }

Chrome和Safari中会显示提醒,而Firefox则保持静音。

这种令人惊讶的,不一致的行为有没有解释?

3 个答案:

答案 0 :(得分:8)

Javascript delarations总是会被移到顶部。它被称为提升

应该适用于所有浏览器的示例: http://jsbin.com/abelus/edit

答案 1 :(得分:3)

您注意到的行为称为function hoisting

简而言之,使用语法function foo() { ... }定义的函数被“提升”到定义它们的作用域的顶部,从而允许在定义之前调用它们。

话虽如此,这是JavaScript的一个不起眼的部分。如果浏览器实现它的方式有所不同(特别是如果你使用的是旧版本的firefox),我不会感到惊讶。

答案 2 :(得分:3)

虽然其他人解释了功能的“提升”行为(我个人觉得称之为上下文准备预处理提升更清晰)Firefox的不同行为的原因仍然没有答案。

首先,您应该知道函数声明和函数声明之间的区别。

函数声明,在您的示例中,只能在两个地方,全局代码(在任何函数之外)并且直接在另一个函数的Function Body中发生,例如:

function foo () {}

function bar () {
  function baz() {}
}

以上所有功能都是有效的功能声明。

ECMAScript规范不允许在其他地方定义函数声明,例如在Blocks:

if (true) {
  function foo () {}
}

上面的函数应该给你一个SyntaxError异常,但是大多数实现是仁慈的,并且他们仍然会预处理(提升)函数,即使实际函数不是可达的(例如if (false) { function bar() {} })。

在Firefox中,允许使用功能语句,这意味着当控件到达特定语句时,实际上会发生函数定义,例如:

if (true) {
  function foo () { return true; }
} else {
  function foo () { return false; }
}

在上述语句之后执行foo();,在Firefox中将生成true,因为if语句的第一个分支实际上已执行。

在其他浏览器中,foo();生成false,因为所有函数在进入执行上下文时都会被预处理,而最后一个函数优先,即使false分支也是如此。 if语句从未到达。

Firebug控制台执行将其包装在try-catch块内的代码,这就是在声明之前的功能。

如果您尝试使用控制台:

console.log(typeof f); // "undefined"
function f () {}

您将看到f尚未准备好,但如果您将代码包装在函数中,您将看到预期的行为:

(function () {
  console.log(typeof f); // "function"
  function f () {}
})();

同样,那是因为现在f被定义为函数声明,因为它存在于匿名函数的主体中,并且不是语句块的一部分。