此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
提升
JavaScript 提升是指解释器在执行代码之前,似乎将函数、变量、类或导入的声明移动到其作用域的顶部的过程。
提升不是 ECMAScript 规范中规范定义的术语。规范确实将一组声明定义为可提升的声明,但这只包括 function、function*、async function 以及 async function* 声明。提升通常也被认为是 var 声明的一个特性,尽管方式不同。用通俗的话来说,以下任何行为都可以被视为提升:
- 能够在声明变量之前在其作用域中使用该变量的值。("值提升")
- 能够在声明变量之前在其作用域中引用该变量而不抛出
ReferenceError,但值始终是undefined。("声明提升") - 变量的声明导致在声明行之前的作用域中行为发生变化。
- 声明的副作用在评估包含该声明的其余代码之前产生。
前面说到的四种函数声明的提升表现为第 1 种行为;var 声明的提升表现为第 2 种行为;let、const 和 class 声明(也称为词法声明)的提升表现为第 3 种行为;import 声明的提升表现为第 1 和第 4 种行为。
有些人更倾向于将 let、const 和 class 视为不提升的,因为暂时性死区严格禁止在声明之前使用变量。这种看法是可以接受的,因为提升并不是一个普遍认同的术语。然而,暂时性死区可以导致其作用域内的其他可观察变化,这表明存在某种形式的提升:
const x = 1;
{
console.log(x); // ReferenceError
const x = 2;
}
如果 const x = 2 声明完全没有提升(即仅在执行时生效),那么 console.log(x) 语句应该能够读取上层作用域的 x 值。然而,由于 const 声明仍然"污染"了其定义的整个作用域,console.log(x) 语句读取的是 const x = 2 声明的 x,但它尚未初始化,因此抛出 ReferenceError。不过,从实用角度看,将词法声明视为不提升可能更有用,因为这些声明的提升并没有带来任何有意义的特性。
注意以下情况不属于提升:
{
var x = 1;
}
console.log(x); // 1
这里没有"在声明前访问";只是因为 var 声明不是块级作用域的。
有关提升的更多信息,请参见:
var、let、const提升——语法类型教程function提升——函数教程class提升——类教程import提升——JavaScript 模块