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

zan*_*ngw 13 javascript firefox google-chrome

为什么以下代码在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());
Run Code Online (Sandbox Code Playgroud)

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

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

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

Fab*_*tté 17

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

引用Kangax:

FunctionDeclarations只允许出现在ProgramFunctionBody中.从语法上讲,它们不能出现在Block({ ... })中 - 例如if,while或者for语句.这是因为只能包含声明,不是SourceElements,这FunctionDeclaration是.如果我们仔细查看生产规则,我们可以看到,直接在Block中允许Expression的唯一方法是它是ExpressionStatement的一部分.但是,ExpressionStatement被明确定义为不以"function"关键字开头,这正是FunctionDeclaration不能直接出现在StatementBlock中的原因(注意Block只是一个语句列表).

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

另外值得引用ECMAScript 6草案 - B.3.3块级函数声明Web遗留兼容性语义:

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


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

无论如何,这些都很容易重写为可移植代码:

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

根据ECMAScript 6,函数声明是块作用域的,因此Firefox实现了正确的ES6行为.