为什么以下代码在 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 语言的当前官方规范)没有定义块内函数声明的行为。
Quoting Kangax:
函数声明只允许出现在Program or 函数体。从句法上来说,他们不能出现在Block ({ ... }
)——例如if
, while
or for
声明。这是因为Blocks只能包含声明, not 源元素, which 函数声明是。如果我们仔细观察生产规则,我们会发现唯一的方法表达允许直接在Block是当它是的一部分表达式语句。然而,表达式语句被明确定义不以“function”关键字开头,这正是为什么函数声明不能直接出现在陈述 or Block(注意Block只是一个列表声明).
由于这些限制,只要函数直接出现在块中(例如在前面的示例中),它实际上应该是被认为是语法错误,不是函数声明或表达式。问题是我见过的几乎没有一个实现严格按照规则解析这些函数(BESEN 和 DMDScript 除外)。相反,他们以专有的方式解释它们。
还值得引用的是ECMAScript 6 草案 - B.3.3 块级函数声明 Web 遗留兼容性语义:
在第六版之前,ECMAScript 规范没有定义 a 的发生函数声明作为 Block 语句的元素声明列表。然而,对这种形式的支持函数声明是一个允许的扩展,并且大多数浏览器托管的 ECMAScript 实现都允许它们。不幸的是,这些声明的语义在这些实现之间有所不同。 [...]
由于 ES5 没有定义块内函数声明的行为,同时允许专有扩展,因此技术上不存在“正确”或“错误”。将它们视为“未指定的行为”,无法跨不同的 ES5 兼容环境移植。
无论如何,这些很容易重写为可移植代码:
- 函数声明是否应该提升到当前函数/全局作用域的顶部?确保函数声明不直接位于块内。
- 是否应该仅在块执行时声明函数?将函数表达式分配给变量 (
var f = function() {};
)。请注意,没有提升,并且变量仍然可以在块之外访问(var
声明是函数级范围的)。
根据 ECMAScript 6,函数声明是块作用域的,因此 Firefox 实现了正确的 ES6 行为。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)