有问题的代码很简单:
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则保持静音。
这种令人惊讶的,不一致的行为有没有解释?
答案 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
被定义为函数声明,因为它存在于匿名函数的主体中,并且不是语句块的一部分。