var foo = function(){ return 1; };
if (true) {
function foo(){ return 2; }
}
foo(); // 1 in Chrome // 2 in FF
//I just want to be sure, is FF 4 not "standard" in this case?
编辑:
如果我们有这个:
var foo = function(){ return 1; };
if (true) function foo(){ return 2; }
foo(); // is 1 standard or is 2 standard?
答案 0 :(得分:31)
ECMAScript标准不允许使用原始海报的代码。 (ECMAScript是JavaScript语言规范的官方名称,出于法律原因。)然而,它是该语言的常见扩展 - 不幸的是,它在不同的浏览器中以不同的方式实现。
在标准JavaScript中,函数定义可能只出现在顶级代码中,或者出现在函数体的顶层。在封闭函数的主体和函数定义之间不能有条件,循环,甚至花括号。
例如,允许这样做:
function f() {
function g() {
...
}
}
但这不是:
function f() {
{
function g() {
...
}
}
}
图片的复杂之处在于大多数浏览器做接受后一个代码,但每个代码都为其分配了自己的特殊解释。 Firefox将其视为:
function f() {
{
var g = function g() {
...
}
}
}
ECMAScript委员会正在考虑为这些“功能陈述”选择一种特定的解释(而不是功能定义)。他们还没有做出决定。 Mozilla正在讨论其首选解决方案here。
答案 1 :(得分:16)
当前的ECMAScript语法实际上根本不允许使用该问题中的代码(从ECMAScript 5开始)。您可以在块内执行var foo = function() {}
,但只能在函数或脚本的顶层执行function foo() {}
。
目前,浏览器以不兼容的方式支持问题中的代码,因为它们都实现了核心语言的扩展,并且实现了不同的扩展。完全符合ECMAScript 5的实现在编译此脚本时实际上会以SyntaxError结束。
有些建议要为ECMAScript添加执行此类操作的功能,但它们还没有最终完成。
答案 2 :(得分:12)
根据ECMAScript标准,两者在技术上都是错误的,因为函数声明只允许在顶层或直接在其他函数内部。从技术上讲,if
块中的函数声明是语法错误。大多数实现允许它作为扩展,但它们以不同的方式解释它。
差异的原因是Chrome将foo
“声明”视为正常的函数声明并将其提升到范围的开头。 Firefox(由于历史原因IIRC)仅在执行if
语句时声明该函数。
为了更好地展示差异,您可以尝试运行此类似的代码:
console.log(foo()); // 2 in Chrome, error in FF
var foo = function(){ return 1; };
console.log(foo()); // 1 in both Chrome and FF
if (true) {
function foo(){ return 2; }
}
console.log(foo()); // 1 in Chrome // 2 in FF
编辑:您的第二个示例完全相同。 JavaScript没有块范围,只有函数级和程序级。 “问题”不是函数声明在一个块中,而是它不是顶级语句。
答案 3 :(得分:11)
在程序的顶层或函数体的顶层找不到函数声明的指定行为。或者说,指定的行为是语法错误,因为JavaScript语法不允许此类函数声明。不同行为的原因在于浏览器历史上一直存在于地图中,并且由于现有网站使用特定于浏览器的代码路径编写而无法让任何人更改,因此它们仍然存在。
Strict mode prohibits this syntax,这是值得的,而ECMAScript的未来版本很可能会定义它。但是现在你不应该使用它,因为它的行为不是由规范精确定义的,你会在不同的浏览器中得到不同的行为。
答案 4 :(得分:1)
fiddle。这是未定义的行为。一团糟。
firefox如何解释它由其他答案处理
Chrome如何解释
var foo = function() { return 1 };
if (true) {
function foo() {
return 2;
}
}
console.log(foo());
正在发生的事情是function foo
被声明然后立即用局部变量foo
覆盖。
这会被翻译成
function foo() {
return 2;
}
var foo;
foo = function() { return 1 };
if (true) { }
console.log(foo());