为什么条件块中的函数声明在Chrome中升级到功能范围而不是Firefox?

时间:2014-08-04 02:37:29

标签: 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());

在Chrome中:结果为false。但是,在Firefox中,它是true

上述代码的关键行是第4行,根据我对函数名称提升的了解,函数g应该在第6行,即第2行被第6行覆盖.IMO,the Chrome的行为是正确的。

我是对的吗?如果是这样,为什么Firefox输出不同的结果?

1 个答案:

答案 0 :(得分:16)

ECMAScript 5,JavaScript语言的当前官方规范,没有定义块内函数声明的行为。

引用Kangax

  

FunctionDeclarations 仅允许出现在 Program FunctionBody 中。从语法上讲,它们不能出现在阻止 { ... })中 - 例如ifwhile或{{1} }语句。这是因为 Blocks 只能包含 Statements ,而不是 SourceElements FunctionDeclaration 。如果我们仔细查看生产规则,我们可以看到,直接在 Block 中允许 Expression 的唯一方法是它是 ExpressionStatement 的一部分。但是, ExpressionStatement 明确定义以不以“function”关键字开头,这正是 FunctionDeclaration 不能直接出现在中的原因声明阻止(请注意阻止只是语句的列表)。

     

由于这些限制,只要函数直接出现在块中(例如在前面的示例中),它实际上应该被认为是语法错误,而不是函数声明或表达式。问题是我见过的几乎没有一个实现严格按照规则解析这些函数(例外是BESEN和DMDScript)。他们用专有的方式解释它们。

还值得引用ECMAScript 6 draft - B.3.3 Block-Level Function Declarations Web Legacy Compatibility Semantics

  

在第六版之前,ECMAScript规范没有将 FunctionDeclaration 的出现定义为Block语句的 StatementList 的元素。但是,支持这种形式的 FunctionDeclaration 是一个允许的扩展,大多数浏览器托管的ECMAScript实现允许它们。不幸的是,这些声明的语义在这些实现中是不同的。 [...]


由于ES5没有在允许专有扩展的情况下定义块内函数声明的行为,因此技术上没有“权限”或“错误”。将它们视为“未指定的行为”,这些行为在不同的ES5兼容环境中无法移植。

无论如何,这些都很容易重写为便携式代码:

  • 是否应将函数声明提升到当前函数/全局范围的顶部?确保函数声明不直接在块内。
  • 只有在块执行时才能声明函数吗?将函数表达式赋给变量(for)。请注意,没有提升,并且仍然可以在块外部访问变量(var f = function() {};声明是功能级范围的。)

根据ECMAScript 6,函数声明是块范围的,因此Firefox实现了ES6的正确行为。