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

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

问题描述

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

  f = function(){return true;}; 
g = function(){return false;};
(function(){
if(g()&& [] ==![]){
f = function f(){return false;};
函数g(){return true;}
}
})();
console.log(f());

在Chrome中:结果是 false 。然而,在Firefox中,它是 true



上面代码的关键是第4行,base根据我对函数名称提示的知识,函数 g 应该在第6行,即第2行被第6行覆盖。IMO的行为是正确的。 / p>

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

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



引用 Kangax
$ b


FunctionDeclarations 只允许出现在 FunctionBody 。在语法上,不能出现在 Block {...} )中,例如 if while for 语句。这是因为 Blocks 只能包含 Statements ,而不是 FunctionEclaration 所在的 SourceElements 。如果我们仔细查看生产规则,我们可以看到直接在 Block 中允许 Expression 的唯一方式是当它是 ExpressionStatement 的一部分时。然而, ExpressionStatement 是明确定义的不能以function关键字开头,这正是为什么 FunctionDeclaration 不能直接出现在声明 Block (请注意, Block 仅仅是语句的列表)。

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


另外值得引用 / p>


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






由于ES5没有定义函数声明的行为同时允许专有扩展,在技术上没有权利或错误。把它们看作是不确定的行为,不能在不同的符合ES5标准的环境中移植。



这些很容易被重写成便携式代码:


  • 函数声明应该被提升到当前函数/全局范围的顶部吗?确保函数声明不是直接在块中。

  • 只有当程序块执行时才能声明函数。将函数表达式分配给变量( var f = function(){}; )。请注意,没有提升,变量仍然可以在块之外访问( var 声明是函数级别的作用域)






根据ECMAScript 6,函数声明是块范围的,所以Firefox实现了正确的ES6方式。 b $ b

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());

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

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.

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

解决方案

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

Quoting Kangax:

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).

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.

Also worth quoting the ECMAScript 6 draft - B.3.3 Block-Level Function Declarations Web Legacy Compatibility Semantics:

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. [...]


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:

  • 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).

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

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

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