如何处理函数声明?
var abc = '';
if(1 === 0){
function a(){
abc = 7;
}
}else if('a' === 'a'){
function a(){
abc = 19;
}
}else if('foo' === 'bar'){
function a(){
abc = 'foo';
}
}
a();
document.write(abc); //writes "foo" even though 'foo' !== 'bar'
此示例在Chrome和Firefox中生成不同的输出。当{FF}输出foo
时,Chrome输出19
。
答案 0 :(得分:52)
当提出这个问题时,ECMAScript 5(ES5)很普遍。在ES5的严格模式下,函数声明不能嵌套在if
块内,如问题所示。在非严格模式下,结果是不可预测的。不同的浏览器和引擎实现了他们自己处理块内函数声明的规则。
截至2018年,许多浏览器都支持ECMAScript 2015(ES2015),范围为function declarations are now allowed inside blocks。在ES2015环境中,块内的函数声明将作用于该块内。问题中的代码将导致未定义的函数错误,因为函数a
仅在if
语句的范围内声明,因此不存在于全局范围内。
如果您需要有条件地定义一个函数,那么您应该使用function expressions。
答案 1 :(得分:7)
来自http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
在javascript中,你有函数声明:
function foo() {
}
和函数表达式
var foo = function() {
}
引自http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
“始终移动函数声明和函数变量 ('hoisted')由JavaScript构成JavaScript范围的顶部 解释器”。
所以在你的第一个例子中发生的是function a()
的函数声明被提升到Javascript范围的顶部,因此即使if计算为false,也会产生'foo'
将var foo
视为普通的Javascript语句,它只在您的javascript运行时执行,与function foo()
不同,这就是为什么以下内容有效:
alert(foo());
function foo() {
return 'gw ganteng';
}
此处,function foo()
由解析器解析,在尝试调用foo()
alert(foo())
置于当前作用域中
http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
在JavaScript执行中有Context(ECMA 5闯入 LexicalEnvironment,VariableEnvironment和ThisBinding)和Process (一组要按顺序调用的语句)。声明 在执行范围为时,对VariableEnvironment做出贡献 进入。它们与陈述(例如归还)不同 不受其处理规则的约束。
答案 2 :(得分:1)
ECMA-262 v5要求实现在输入任何新的全局或函数级执行上下文时在第一次传递期间注册所有函数和变量声明。从技术上讲,Chrome就是在这里进行的,因为它会查看else
和then
块并在执行前注册a()
。不幸的是,它产生了最难以理解的结果。
FF正在等待,直到它在评估之前评估if语句并将函数和变量声明添加到当前上下文。 BTW。两个浏览器都在catch和finally子句中这样做。
这只是两个不同的ECMA实现的问题,处理一个不应该开始的功能。手头的场景显示了为什么函数声明不应该在控制流语句中。
答案 3 :(得分:0)
{}
块之外无法访问函数声明。if (true) {
function sayHi() {
alert("hii");
}
sayHi(); //accessible
}
sayHi(); //error, not accessible since out of the block
let sayHi;
if (true) {
sayHi = function(){
alert("hii");
}
sayHi(); //accessible
}
sayHi(); //accessible