我被问到一个问题
{
function foo() {
console.log('A');
}
foo();
foo = 1;
function foo() {
console.log('B');
}
foo = 2;
console.log(foo);
}
console.log(foo);
为什么使用第三个输出1
而不是2
?
应该没有作用域块foo
创建以来,既没有let
,也不const
在该块。但是第二个foo
输出2
表示确实存在另一个引用foo
。
到底是怎么回事?
PS我正在使用Chrome
Version 89.0.4389.90 (Official Build) (x86_64)
。
根据函数声明处的网络兼容语义,已阻止范围变量的值绑定到外部范围²。此代码等效于:
let outerFoo; // the functions create a binding outside of the scope
{
let innerFoo; // but also inside
// due to hoisting, functions get bound before any code get's executed:
innerFoo = function foo() {
console.log('A');
};
innerFoo = function foo() {
console.log('B');
};
// At the place of the function declaration, the variable leaves the scope
/* function foo() {
console.log('A');
} */
outerFoo = innerFoo;
innerFoo();
innerFoo = 1;
// this also applies to the second declaration
/* function foo() {
console.log('B');
} */
outerFoo = innerFoo;
innerFoo = 2;
console.log(innerFoo);
}
console.log(outerFoo);
²这基本上就是规范描述的方式:
When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6: a. Let fenv be the running execution context's VariableEnvironment. b. Let benv be the running execution context's LexicalEnvironment. c. Let fobj be ! benv.GetBindingValue(F, false). d. Perform ! fenv.SetMutableBinding(F, fobj, false).
规范另外指出:
在ECMAScript 2015之前,ECMAScript规范未将FunctionDeclaration的出现定义为Block语句的StatementList的元素。但是,对这种形式的FunctionDeclaration的支持是一个允许的扩展,大多数浏览器托管的ECMAScript实现都允许它们。不幸的是,这些声明的语义在这些实现之间有所不同。由于存在这些语义差异,因此,使用块级功能声明的现有Web ECMAScript代码仅在用法仅取决于此类声明的所有浏览器实现的语义交集的情况下,才可在浏览器实现中移植。
因此,Safari可能会像往常一样执行此操作,而Chrome(和Firefox)则遵循该规范。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句