注意:请参阅答案末尾的更新,块内的声明变得有效(但如果您不使用严格模式,则相当复杂)。
这是一个原因:
var whatever;
if (some_condition) {
whatever = function() {
// Do something
};
}
else {
whatever = function() {
// Do something else
};
}
whatever();
您可能会在必须处理实现差异(例如 Web 浏览器之间的差异、a'la IEattachEvent
与标准之间的差异)的库的初始化中看到类似的代码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() {
// ...
}
第一个是函数表达式,当代码在上下文的逐步执行中到达该点时(例如,它所在的函数,或全局代码的逐步执行),它会被评估。它还会产生一个匿名函数(引用它的变量有一个名称,但该函数没有,这对帮助您的工具帮助您有影响)。
第二个是函数声明,它在进入上下文时进行评估,然后执行任何分步代码。(有些人称其为“提升”,因为源中更深的东西比源中更高的东西发生得更早。)该函数也被赋予了一个专有名称。
所以考虑:
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
也是“提升”)。
并结束:目前,您不能在一般的客户端网络内容中执行此操作:
var bar = function foo() { // <=== Don't do this in client-side code for now
// ...
};
你应该能够做到这一点,它被称为命名函数表达式,它是一个函数表达式,它为函数提供了一个正确的名称。但是各种 JavaScript 引擎在不同时期都出错了,而IE 直到最近才继续出错。
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 引擎之间有所不同。我不会在这里讨论它。只是不要这样做。如果您坚持在块中声明函数,请使用严格模式,在这种模式下它们有意义并且跨环境保持一致。