JS变量声明提升

首先来看一段代码

console.log(a)
var a = 2;
输出结果是2,正常来说JS如果是逐行向下执行,那么应该输出undefined,为何此处输出2呢?

原因在于JS在执行前都会进行编译(通常就在执行前),在编译过程中包括变量和函数在内的所有声明都会被处理。

定义

是指在 JavaScript 代码执行前的编译过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认undefined。

那let,const是否会进行变量声明提升呢?

首先我们要知道定义一个JS变量分为三个阶段

  • 创建create
  • 初始化initialize
  • 赋值assign

下面我们分别来看看var、let、function 和 const的过程

var声明

function fn() {
  var x = 1;
}
fn();
  • 进入 fn,为 fn 创建一个环境。
  • 找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
  • 将这些变量「初始化」为 undefined。
  • 开始执行代码
  • x = 1 将 x 变量「赋值」为 1

 由以上步骤可知,var 声明会在代码执行之前就将创建变量,并将其初始化为 undefined。即创建和初始化会被提升

function声明

fn();
function fn() {
  console.log(1);
}
  • 找到所有用 function 声明的变量,在环境中「创建」这些变量。
  • 将这些变量「初始化」并「赋值」为 function(){ console.log(1) }。
  • 开始执行代码 fn2()

由以上步骤可知,function 的「创建」「初始化」和「赋值」都被提升了

let声明

{
  let x = 1;
  x = 2;
}
  • 找到所有用 let 声明的变量,在环境中创建这些变量
  • 开始执行代码(注意现在还没有初始化)
  • 执行 x = 1,将 x 初始化为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
  • 执行 x = 2,对 x 进行赋值

由以上步骤可知,let只有创建过程会提升,初始化和赋值都不会提升,所以会形成暂时性死区,这也是为什么在定义前使用let会抛错。

暂时性死区,就是不能在初始化之前,使用变量

const声明

{
    console.log(x);
  const x = 1;
}
  • 找到所有用 const声明的变量,在环境中「创建」这些变量
  • 开始执行代码(注意现在还没有初始化)
  • 执行x = 1, 将x初始化为1

由以上步骤可知,const的创建过程也会提升,但是与let不同之处在于const只有创建和初始化两个过程,没有赋值过程。若不初始化则会直接抛错

总结

  • var 的创建初始化都被提升了。
  • function 的创建、初始化赋值都被提升了。
  • let 的创建被提升了,但是初始化和赋值没有提升。
  • const的创建被提升但是初始化没提升。const没有赋值。

注意⚠️

函数优先

何为函数优先,来看一下下面的代码👇

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

实际上输出值会是1,因为当变量声明和函数声明同时存在时,函数声明优先于变量声明,即函数声明会覆盖变量声明。原因在于函数的赋值过程也会提升。那有人可能有疑问,如果将var变成let呢?结果为foo不允许被重复声明。

变量提升的存储位置

执行上下文中存在一个变量环境的对象(Viriable Environment),该对象中保存了变量提升的内容。而let,const则存在词法环境中。

浏览器原理与实践

//www.jianshu.com/p/0f49c88cf169