Hao*_* Wu 26 javascript hoisting
我被问到一个问题
{
function foo() {
console.log('A');
}
foo();
foo = 1;
function foo() {
console.log('B');
}
foo = 2;
console.log(foo);
}
console.log(foo);
Run Code Online (Sandbox Code Playgroud)
为什么第三个输出是1
而不是2
?
不应该foo
创建块作用域,因为该块中既没有let
也没有const
。但是第二个foo
输出2
意味着确实foo
已经创建了另一个引用。
到底是怎么回事?
PS 我正在使用 Chrome
Version 89.0.4389.90 (Official Build) (x86_64)
。
根据函数声明处的web compat 语义,阻塞作用域变量的值绑定到外部作用域²。此代码等效于:
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);
Run Code Online (Sandbox Code Playgroud)
²这基本上就是规范描述它的方式:
Run Code Online (Sandbox Code Playgroud)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)则遵循规范。
归档时间: |
|
查看次数: |
391 次 |
最近记录: |