Javascript 为什么条件块中的函数声明被提升到Chrome中的函数范围,而不是Firefox中的函数范围?
为什么以下代码在Chrome和Firefox之间输出不同的结果Javascript 为什么条件块中的函数声明被提升到Chrome中的函数范围,而不是Firefox中的函数范围?,javascript,google-chrome,firefox,Javascript,Google Chrome,Firefox,为什么以下代码在Chrome和Firefox之间输出不同的结果 f = function() {return true;}; g = function() {return false;}; (function() { if (g() && [] == ![]) { f = function f() {return false;}; function g() {return true;} } })(); console.log(f
f = function() {return true;};
g = function() {return false;};
(function() {
if (g() && [] == ![]) {
f = function f() {return false;};
function g() {return true;}
}
})();
console.log(f());
在Chrome中:结果为false
。然而,在Firefox中,它是真的
以上代码的关键行是第4行,根据我对功能名称提升的了解,功能g
应该在第6行,即第2行被第6行覆盖。依我看,铬的行为是正确的
我说的对吗?如果是这样,为什么Firefox会输出不同的结果?当前JavaScript语言的官方规范ECMAScript 5没有定义块内函数声明的行为 引述: 函数声明只允许出现在程序或函数体中。从语法上讲,它们不能出现在块中(
{…}
)-例如if
,while
或for
语句。这是因为块只能包含语句,而不能包含FunctionDeclaration所定义的SourceElements。如果我们仔细研究产生式规则,我们可以看到,在块中直接允许表达式的唯一方式是当它是ExpressionStatement的一部分时。然而,ExpressionStatement被明确定义为不以“function”关键字开头,这正是FunctionDeclaration不能直接出现在语句或块中的原因(请注意,块只是语句列表)
由于这些限制,每当函数直接出现在块中时(如前一示例中),实际上应将其视为语法错误,而不是函数声明或表达式。问题是,我见过的实现中几乎没有一个严格按照规则解析这些函数(例外是BESEN和DMDScript)。他们以专有的方式解释它们
同样值得引用的是:
在第六版之前,ECMAScript规范没有将FunctionDeclaration的出现定义为块语句的StatementList元素。然而,对这种形式的FunctionDeclaration的支持是允许的扩展,大多数浏览器托管的ECMAScript实现都允许这样做。不幸的是,这些声明的语义在这些实现中有所不同。[……]
由于ES5不定义块内函数声明的行为,同时允许专有扩展,因此从技术上讲,没有“正确”或“错误”。在不同的ES5兼容环境下考虑它们“未指定的行为”。 无论如何,这些都很容易重写为可移植代码:
- 是否应将功能声明提升到当前功能/全局范围的顶部?确保函数声明不直接位于块内部
- 是否应该仅在执行块时声明函数?将函数表达式赋给变量(
)。请注意,没有提升,并且变量仍然可以在块外部访问(var f=function(){};
声明是函数级范围)var
根据ECMAScript 6,函数声明是块范围的,因此Firefox在ES6方面实现了正确的行为。因为Chrome会提升
g
,而Firefox不会。不要在块内使用函数声明。在这种情况下,Firefox实际上更为正确,但仍然存在一些依赖于实现的魔力。看,这应该是一个答案,而不是一个评论。(虽然我认为两者或多或少都不正确,因为结果没有在规范中定义。)@iancleland:我很确定这是一个副本,但我不想在手机上搜索它。if(g()&&&[]=![]){
可以更改为if(g()){
这个例子仍然有效,而且在你回答的最后一句话中更清楚一点,你说函数声明是块范围的,你的意思是它们被提升到块中吗?因为MDN说的是相反的:@pooria即使MDN这么说,如果函数在块中,它们也不会被提升到程序的顶部block.@pooria在本例中也是MDN,如果block在全局范围内不可用,则函数在中。