注意:请参阅答案末尾的更新,块内的声明变得有效(但如果您不使用严格模式,则相当复杂)。
这是一个原因:
var whatever;
if (some_condition) {
whatever = function() {
// Do something
};
}
else {
whatever = function() {
// Do something else
};
}
whatever();
您可能会在必须处理实现差异的库的初始化中看到类似的代码(例如 Web 浏览器之间的差异,例如 IE 的 attachEvent 与标准的 addEventListener)。你不能用函数声明做同样的事情:
if (some_condition) {
function whatever() { // <=== DON'T DO THIS
// Do something
}
}
else {
function whatever() { // <=== IT'S INVALID
// Do something else
}
}
whatever();
...它们没有在控制结构中指定,所以 JavaScript 引擎可以做他们想做的事,不同的引擎做了不同的事情。 (编辑:再次,请参阅下面的注释,它们现在已指定。)
另外,有很大的区别
var whatever = function() {
// ...
};
和
function whatever() {
// ...
}
第一个是函数表达式,当代码在上下文的逐步执行中到达该点时(例如,它所在的函数,或逐步执行- 全局代码的步骤执行)。它还会产生一个匿名函数(引用它的变量有名称,但函数没有,这对helping your tools to help you有影响)。
第二个是函数声明,它在进入上下文时进行评估,在任何分步代码执行之前。 (有些人称其为“提升”,因为源中更底层的事情比源中更高的事情发生得更早。)该函数也被赋予了一个正确的名称。
所以考虑一下:
function foo() {
doSomething();
doSomethingElse();
console.log("typeof bar = " + typeof bar); // Logs "function"
function bar() {
}
}
而
function foo() {
doSomething();
doSomethingElse();
console.log("typeof bar = " + typeof bar); // Logs "undefined"
var bar = function() {
};
}
在第一个示例中,使用声明,在doSomething 和其他逐步代码运行之前处理声明。在第二个例子中,因为它是一个表达式,它是作为逐步代码的一部分执行的,所以函数没有在上面定义(变量在上面定义,因为var is also "hoisted")。
结束:目前,您无法在一般的客户端 Web 内容中执行此操作:
var bar = function foo() { // <=== Don't do this in client-side code for now
// ...
};
您应该能够做到这一点,它被称为命名函数表达式,它是一个函数表达式,它为函数提供了一个正确的名称。但是各种 JavaScript 引擎在不同时期都出错了,IE continued to get very wrong indeed until very recently。
ES2015+ 更新
从 ES2015(又名“ES6”)开始,块内的函数声明被添加到规范中。
严格模式
在严格模式下,新指定的行为简单易懂:它们的范围仅限于它们发生的块,并被提升到它的顶部。
所以这个:
"use strict";
if (Math.random() < 0.5) {
foo();
function foo() {
console.log("low");
}
} else {
foo();
function foo() {
console.log("high");
}
}
console.log(typeof foo); // undefined
(注意对函数的调用是如何在块内的函数之上的。)
...本质上等价于:
"use strict";
if (Math.random() < 0.5) {
let foo = function() {
console.log("low");
};
foo();
} else {
let foo = function() {
console.log("high");
};
foo();
}
console.log(typeof foo); // undefined
松散模式
松散模式的行为要复杂得多,而且理论上它在 Web 浏览器中的 JavaScript 引擎和 Web 浏览器中的 JavaScript 引擎not之间有所不同。我不会在这里讨论它。只是不要这样做。如果您坚持在块中声明函数,请使用严格模式,在这种模式下它们有意义并且跨环境保持一致。