Javascript 根据标准,哪个JS函数声明语法是正确的?
编辑: 如果我们有:Javascript 根据标准,哪个JS函数声明语法是正确的?,javascript,firefox,google-chrome,standards,Javascript,Firefox,Google Chrome,Standards,编辑: 如果我们有: 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? 。这是未定义的行为。一团糟 firefox如何解释它由其他答案处理 chrome如何解读它 var
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?
。这是未定义的行为。一团糟
firefox如何解释它由其他答案处理
chrome如何解读它
var foo = function(){ return 1; };
if (true) function foo(){ return 2; }
foo(); // is 1 standard or is 2 standard?
实际发生的情况是函数foo
被声明,然后立即被局部变量foo
覆盖
这被翻译成
var foo = function() { return 1 };
if (true) {
function foo() {
return 2;
}
}
console.log(foo());
当前ECMAScript语法(从ECMAScript 5开始)实际上根本不允许使用问题中的代码。可以在块内执行
var foo=function(){}
,但只能在函数或脚本的顶层执行function foo(){}
目前浏览器以不兼容的方式支持问题中的代码,因为它们都实现了对核心语言的扩展,并且实现了不同的扩展。编译此脚本时,完全一致的ECMAScript 5实现实际上最终会出现一个语法错误
有人提议将这类功能添加到ECMAScript中,但尚未完全定稿。ECMAScript标准不允许使用原始海报的代码。(出于法律原因,ECMAScript是JavaScript语言规范的官方名称。)然而,它是该语言的通用扩展,不幸的是,在不同的浏览器中实现方式不同 在标准JavaScript中,函数定义只能出现在顶级代码中,或者出现在函数体的顶级。在封闭函数的主体和函数定义之间不能有条件、循环,甚至大括号 例如,这是允许的:
function foo() {
return 2;
}
var foo;
foo = function() { return 1 };
if (true) { }
console.log(foo());
但这不是:
function f() {
function g() {
...
}
}
使情况复杂化的是,大多数浏览器确实接受后一种代码,但每种浏览器都为其指定自己的特殊解释。Firefox将其视为:
function f() {
{
function g() {
...
}
}
}
ECMAScript委员会正在考虑为这些“函数声明”(与函数定义相反)选择特定的解释。他们还没有做出决定。Mozilla正在讨论它的首选解决方案。根据ECMAScript标准,两者在技术上都是错误的,因为函数声明只允许在顶层或直接在其他函数内部进行。从技术上讲,
if
块中的函数声明是语法错误。大多数实现允许它作为扩展,但它们的解释不同
区别的原因是Chrome将foo
“声明”视为一个正常的函数声明,并将其提升到范围的开头。Firefox(出于历史原因IIRC)仅在执行if
语句时声明函数
为了更好地演示差异,您可以尝试运行以下类似代码:
function f() {
{
var g = function g() {
...
}
}
}
编辑:您的第二个示例与此完全相同。JavaScript没有块作用域,只有函数级和程序级。“问题”不在于函数声明在块中,而在于它不是顶级语句。在程序的顶级或函数体的顶级中找不到函数声明的指定行为。或者,更确切地说,指定的行为是语法错误,因为JavaScript语法不允许这样的函数声明。不同行为的原因是浏览器在历史上一直在地图上,并且由于现有网站使用特定于浏览器的代码路径编写,使得任何人都无法更改,所以浏览器仍然如此
,它的价值是什么,很可能ECMAScript的未来版本会定义它。但是现在你不应该使用它,因为它的行为并不是由规范精确定义的,而且在不同的浏览器中你会得到不同的行为。有什么原因让你期望这段代码有可预测的结果吗?@capture你发布的JSFIDLE中的代码与Pracier原始帖子中的代码不匹配。这里有一个合适的例子:我运行的是Chrome,我刚刚创建的JSFIDLE返回1,而囚徒创建的JSFIDLE返回2。@AndrewMoore函数声明被提升到最近的函数范围,而不是块范围。1是正确的。@jamietre Chromes控制台是一个不适合测试东西的地方,我过去用它遇到了很多奇怪的评估错误:/I我想大家的共识就是不要这样做!有趣的是,Firefox并没有搞错提升,而是范围界定错了。它无法提升功能,因为它位于支架内。如果删除
If(true){}
,则FF返回1。我想说的是,这个bug不太可能导致任何问题,但这引起了关于FF作用域如何工作的其他担忧。@jamietre是的,这是正确的。函数声明可能是基于块的。我查过了。只有函数声明是由块解析的。函数被绑定到函数作用域,只是在解析块之前它不会被声明。在任何情况下,任何将函数声明放在条件块中的人都应该得到它们所得到的。Firefox在这里是完全正确的。该程序不允许使用标准ECMAScript代码;相反,它使用了许多浏览器作为扩展实现的语法——每个浏览器都有不同的语义。“Firefox…[是否]范围界定错误”?给我们一点信任吧。@JimBlandy我已经搞定了答案。我不会说firefox是正确的。在块内支持函数声明是未定义的行为。但你是对的,我攻击firefox是不必要的,因为我不明白块中的函数声明是不允许的。我认为Firefox行为的历史原因是,您可以编写if(ie3){function f(){…}或者{function f(){…}}
和if语句来确定您使用的函数。但是,它从来都不是一个健全的语言特性。我用反勾号替换管道以启用代码f
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