为什么以下代码在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,Chrome的行为是正确的。
我对吗?如果是这样,为什么Firefox输出不同的结果?
ECMAScript 5是JavaScript语言的当前官方规范,它没有定义块内函数声明的行为。
引用 Kangax:
FunctionDeclarations 只允许出现在 程序 要么 函数体。从语法上讲,他们 不能出现 块 ({ ... }
) - 比如 if
, while
要么 for
声明。这是因为 块 只能包含 声明不是 SourceElements, 哪一个 FunctionDeclaration 是。如果我们仔细研究生产规则,我们就能看到唯一的方法 表达 允许直接进入 块 是什么时候它的一部分 ExpressionStatement。然而, ExpressionStatement 是明确定义的 不以“function”关键字开头,这正是原因 FunctionDeclaration 不能直接出现在 声明 要么 块 (注意 块 只是一个清单 声明)。
由于这些限制,只要函数直接出现在一个块中(例如在前面的例子中),它实际应该是 考虑语法错误,而不是函数声明或表达。问题是我见过的几乎没有一个实现严格按照规则解析这些函数(例外是BESEN和DMDScript)。他们用专有的方式解释它们。
也值得引用 ECMAScript 6草案 - B.3.3块级函数声明Web遗留兼容性语义:
在第六版之前,ECMAScript规范没有定义a的出现 FunctionDeclaration 作为Block语句的元素 语句列表。但是,支持那种形式 FunctionDeclaration 是一个允许的扩展,大多数浏览器托管的ECMAScript实现允许它们。不幸的是,这些声明的语义在这些实现中是不同的。 [...]
由于ES5在允许专有扩展时没有定义块内函数声明的行为,因此技术上没有“权利”或“错误”。将它们视为“未指定的行为”,这些行为在不同的ES5兼容环境中不可移植。
无论如何,这些都很容易重写为可移植代码:
- 函数声明是否应该提升到当前函数/全局范围的顶部?确保函数声明不直接在块内。
- 是否应该仅在块执行时声明该函数?将函数表达式赋给变量(
var f = function() {};
)。请注意,没有提升,变量仍可在块外部访问(var
声明是函数级范围的)。
根据ECMAScript 6,函数声明是块范围的,因此Firefox实现了正确的ES6行为。