6
我们知道再ES5中的varfunction 的申明都存在又变量提升,ES6中的 letconst 则不存在有变量提升。

var变量提升

console.log(a);
var a =1;

// 等价于

var a ;
console.log(a); // undefined
a = 1; 

js中的 function 也可以看作是变量,也存在变量提升

a(); // 1

function a() {
    console.log(1);
}
总之

JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。


let深入理解
  • let 声明的变量的作用域是块级的;
  • let 不能重复声明已存在的变量;
  • let 有暂时死区,不会被提升。
// case1
var liList = document.querySelectorAll('li') // 共5个li
for( var i=0; i<liList.length; i++){
  liList[i].onclick = function(){
    console.log(i)
  }
}

// case2
var liList = document.querySelectorAll('li') // 共5个li
for( let i=0; i<liList.length; i++){
  liList[i].onclick = function(){
    console.log(i)
  }
}

依次点击会出现5个 5 。如果把var 改为了let 就是分别打印0 , 1 , 2, 3, 4 了。

我的理解是:

  1. for(let i = 0; i< 5; i++) 这句话的圆括号之间存在有一个隐藏的作用域
  2. 再每次执行循环体的时候都会在循环体上下文中重新初始化一次
var liList = document.querySelectorAll('li') // 共5个li
for( let i=0; i<liList.length; i++){
  let i = 隐藏作用域中的i // 看这里看这里看这里
  liList[i].onclick = function(){
    console.log(i)
  }
}
// 那样的话,5 次循环,就会有 5 个不同的 i,console.log 出来的 i 当然也是不同的值。

下面我们再来仔细刨析一下具体声明的过程

var变量声明的创建、初始化和赋值过程

function fn(){
    var a = 0;
    var b = 1;
}

fn();

过程分析:

  1. 进入fn,为其创建一个环境
  2. 找出fn中所有声明的变量,在这个环境中创建这些变量(a,b)
  3. 将这些变量初始化为undefined
  4. 开始执行代码
  5. a 赋值 0,b 赋值 1;

这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。

function的声明的创建、初始化、和赋值过程

f2(); // 2

function f2() {
    console.log(2);
}

过程分析:

  1. 找到function声明的变量,在环境中创建
  2. 将这些变量初始化并赋值, function(){ console.log(2) }。
  3. 开始执行代码 fn(); //2

let声明的创建、初始化、赋值

{
  let x = 1
  x = 2
}

过程分析:

  1. 找到let变量在环境中创建,
  2. 开始执行代码 ,注意还没有进行初始化哦
  3. 执行x = 1; x 初始化为 1
  4. 执行x = 2; x 进行赋值

我们再来理解一下let 之前不能使用的原因

{
    console.log(a);
    let a  = 1;
}

原因:

  1. console.log(a) 中的 a 指的是下面的 a,
  2. 执行 log 时 x 还没「初始化」,所以不能使用(也就是暂时性死区)

总结

let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。

最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。

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


参考文献


Meils
1.6k 声望157 粉丝

前端开发实践者