在 JavaScript 的世界中,变量提升是一个将变量声明或者函数声明提升到作用域起始处的过程。

变量的生命周期

当引擎使用变量时,它们的生命周期包含以下阶段:

  • 声明阶段,这一阶段在作用域中注册了一个变量
  • 初始化阶段, 这一阶段分配了内存并在作用域中让内存与变量建立了一个绑定,变量会被自动初始化为 undefined
  • 赋值阶段,这一阶段为已初始化的变量分配具体的一个值

注意,声明阶段与我们通常所说的变量声明是不同的术语。

var 生命周期

网络不给力

假设这样一个场景:当解释器刚进入一个包含 var variable 的作用域时,则在任何语句执行之前,变量就已完成了声明阶段初始化阶段,且值为 undefined。语句 varibale = 'value'赋值阶段

// 在刚进入到 func 作用域时,a 已完成了声明和初始化阶段,且值为 undefined
function func() {
  console.log(a); // undefined
  var a = 1; // 赋值阶段
  console.log(a); // 1
}
func();

function 生命周期

网络不给力

对于 function声明、初始化和赋值阶段在解释器刚进入函数作用域时,便已全部完成。

可以结合以下的代码,去理解 function 的变量提升过程。

// function 提升优先级比 var 和 let 高
foo(); // 2

// 具名函数表达式的函数名只在函数内部有效
bar(); // ReferenceError

function foo() {
  console.log(1);
}

// 多个函数声明时,后面的函数声明会覆盖之前的函数声明
function foo() {
  console.log(2);
}

// 函数声明会被提升,但函数表达式不会被提升
var foo = function bar() {
  console.log(3);
};

foo(); // 3

let 变量的生命周期

网络不给力

let 的提升是只针对声明阶段的提升。

假设这样一个场景:当解释器刚进入一个包含 let variable 的作用域时,就已完成了声明阶段

从声明阶段结束到初始化阶段开始, 这段区域被称为临时死区。如果在这时访问 variable ,将会抛出 ReferenceError: variable is not defined

当解释器执行完 let variable ,变量就已完成了初始化阶段,离开了临时死区,并具有 undefined 的值。之后的语句 variable = 'value'赋值阶段

如果解释器遇到了 let variable = 'value' ,则完成了初始化赋值阶段。

总结

至此,总结一下变量提升过程中的一些重要知识点:

  • var 只有声明阶段初始化阶段被提升
  • function声明阶段初始化阶段赋值阶段都被提升
  • let 只有声明阶段被提升
  • function 提升优先级比 varlet 高,且对于多个函数声明,后面的声明会覆盖前面的声明
  • 函数表达式无法被提升

参考资料