为什么条件块中的函数声明被提升到 Chrome 中的函数范围而不是 Firefox? [英] Why is a function declaration within a condition block hoisted to function scope in Chrome but not Firefox?

查看:19
本文介绍了为什么条件块中的函数声明被提升到 Chrome 中的函数范围而不是 Firefox?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么以下代码在 Chrome 和 Firefox 之间输出不同的结果?

Why the following codes output different results between Chrome and 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.

In Chrome: the result is false. However, in Firefox, it is true.

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

The key line of the above codes is line 4, and base on my knowledge of function name hoisting, the function g should be in line 6, namely the line 2 is overridden by line 6. IMO, the behavior of Chrome is correct.

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

Am I right on this? if so, why Firefox outputs different results?

推荐答案

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

ECMAScript 5, the current official specification of the JavaScript language, does not define the behavior for function declarations inside blocks.

引用 Kangax:

FunctionDeclarations 只允许出现在 ProgramFunctionBody 中.在语法上,它们不能出现在 Block ({ ... }) 中——例如 ifwhilefor 语句.这是因为 Blocks 只能包含 Statements,而不能包含 SourceElements,而 FunctionDeclaration 就是这样.如果我们仔细查看产生式规则,我们会发现 Expression 允许直接在 Block 中的唯一方式是当它是 ExpressionStatement 的一部分时.但是,ExpressionStatement 被明确定义不以function"开头.关键字,这正是 FunctionDeclaration 不能直接出现在 StatementBlock 中的原因(注意 Blockem> 只是一个语句的列表).

FunctionDeclarations are only allowed to appear in Program or FunctionBody. Syntactically, they can not appear in Block ({ ... }) — such as that of if, while or for statements. This is because Blocks can only contain Statements, not SourceElements, which FunctionDeclaration is. If we look at production rules carefully, we can see that the only way Expression is allowed directly within Block is when it is part of ExpressionStatement. However, ExpressionStatement is explicitly defined to not begin with "function" keyword, and this is exactly why FunctionDeclaration cannot appear directly within a Statement or Block (note that Block is merely a list of Statements).

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

Because of these restrictions, whenever function appears directly in a block (such as in the previous example) it should actually be considered a syntax error, not function declaration or expression. The problem is that almost none of the implementations I've seen parse these functions strictly per rules (exceptions are BESEN and DMDScript). They interpret them in proprietary ways instead.

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

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

Prior to the Sixth Edition, the ECMAScript specification did not define the occurrence of a FunctionDeclaration as an element of a Block statement’s StatementList. However, support for that form of FunctionDeclaration was an allowable extension and most browser-hosted ECMAScript implementations permitted them. Unfortunately, the semantics of such declarations differ among those implementations. [...]

<小时>

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


As ES5 does not define the behavior for function declarations inside blocks while allowing proprietary extensions, there are technically no "rights" or "wrongs". Consider them "unspecified behavior" which is not portable across different ES5-compliant environments.

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

Those are easy to rewrite into portable code anyway:

  • 是否应该将函数声明提升到当前函数/全局作用域的顶部?确保函数声明不是直接在块内.
  • 是否应该仅在块执行时声明函数?将函数表达式分配给变量 (var f = function() {};).请注意,没有提升,并且变量仍然可以在块外访问(var 声明是函数级范围的).
  • Should the function declaration be hoisted to the top of the current function/global scope? Make sure the function declaration is not directly inside of a block.
  • Should the function be declared only when the block executes? Assign a function expression to a variable (var f = function() {};). Note that there is no hoisting and the variable is still accessible outside of the block (var declarations are function-level scoped).

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

As per ECMAScript 6, function declarations are block-scoped, so Firefox implements the correct behavior ES6-wise.

这篇关于为什么条件块中的函数声明被提升到 Chrome 中的函数范围而不是 Firefox?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆