var const let 区别pass

我心飞翔 分类:javascript

导言:ES6引入了const let 从而引入了块作用域的概念,使JS的内容更为丰富,那么var const let这三者的区别是什么呢?

区别

  1. const let 具有块状作用域的作用,var 没有
  2. var 具有变量提升的特点,const let不具有
  3. 在声明语句之前访问const let 所声明的变量会报错,这也是第二点的补充

块状作用域

es6之前只有函数作用域全局作用域,除开这两个作用域,在{}内部用var声明的变量是在外部是可以正常访问的,es6之后出现了块状作用域,即引入了let const,使得{}也有了作用域的功能,即在{}内定义const let,外部无法访问let const所定义的变量,如下代码:

// var
function testVar(){
    if(1) {
        var b = 3;
    }
    console.log(b);  
}
testVar(); // 3

// let
function testLet(){
    if(1) {
        let b = 3;
    }
    console.log(b);
}
testLet(); // error: Uncaught ReferenceError: b is not defined
 

变量提升

在作用域中,用var所声明变量,是可以提前访问的,只不过该值为undefined,而const let则会报错;

// var
function testVar(){
    console.log(b); // undefined
    var b = 3;
}
testVar(); 

// let
function testLet(){
    console.log(b); // Uncaught ReferenceError: Cannot access 'b' before initialization
    let b = 3;
}
testLet(); 
 

简单的说,其实就是对于var的声明而言,会做类似以下的操作:

// 模拟var的变量提升
function testVar(){
    var b = undefined;
    console.log(b);
    b = 3;
}
testVar();
 

所以它正常输出了

那都是对变量进行声明的操作,为什么两者有如此区别呢?(const let算是同一者,因为它们之间只是一个声明变量,一个声明常量的区别而已)

JS代码的执行过程

造成两者如此差别的原因,就得从一段JS代码的执行过程开始说起!

// 一段JS代码
test();
console.log(testVar);

function test(){
    console.log('test function');
}
var testVar = 'testVar';
 

上述一段代码,在JavaScript引擎是怎么执行的呢?
其实JavaScript引擎执行一段代码的过程分两个阶段

  1. 编译阶段
  2. 执行阶段

JS代码执行流程.png

编译阶段

在编译阶段过程中,代码会分为两部分

  1. 执行上下文
  2. 可执行代码

执行上下文中,分为两个部分一个部分为变量环境,另外一个部分为词法环境

变量环境里面放的就是变量声明以及函数声明,其实这就是变量提升的实际操作,引擎为test函数以及testVar开辟出内存,内存里面的初始化,如testVarundefined而函数声明则直接是函数体,这也是为什么test函数以及testVar在前面能正常执行;

// 模拟编译完之后的代码的执行顺序,模拟!!实际并不是这样
function test(){
    console.log('test function');
}
var testVar = undefined;

test();
console.log(testVar);
testVar = 'testVar';
 

执行阶段

而执行阶段就要简单得多:

  1. test函数入栈执行
  2. testVar赋值为'testVar'

那么来看看const let的块状作用域是怎么编译的?

// 一段含有let,const的JS代码
    var a = 1;
    var b = 2;
    let c = 3;
    {
        var d = 4;
        let e = 5;
        var f = 6;
    }
 

执行过程:

JS代码执行流程 (1).png

之前编译阶段的词法环境终于用上场了

在这里,var声明的变量,不管是在{}外面还是里面,都会放在变量环境里面做变量提升的操作,而let以及const声明的变量,则会进入到词法环境中类似一个结构一样,被维护起来

具体流程如下:

  1. a,b,d,f进入变量环境变量提升
  2. {}外的d先入词法环境
  3. {}内的e后入词法环境

至此,完成编译阶段

执行阶段是如何访问这些变量的呢

先从词法环境栈顶开始访问,一直到栈底,最终返回到变量环境进行访问

如: a = 1赋值语句先从词法环境栈顶开始访问,一直到栈底,最终返回到变量环境进行访问,最终给a赋值为1,而c = 3则直接从词法环境访问到了,就不进入变量环境

JS代码执行流程 (2).png

当然,词法环境中的变量是被{}限定的,每一次入栈对应的是一个作用域,如c则是全局的作用域,所以只能在全局上下文中被访问到,而e则是在{}内的作用域,只能在{}中被访问到,{}中的代码执行完后,e的词法作用域出栈,变量被销毁,就如同函数的出入栈一致

总结

const letvar的区别主要是:

  1. const let 具有块状作用域的作用,var 没有
  2. var 具有变量提升的特点,const let不具有
  3. 编译阶段var放入到变量环境中,而const var 放入到词法环境中,并维护一个类似词法作用域栈

本文内容为自己对var const let三者区别的总结与归纳,如有问题,请指正!

回复

我来回复
  • 暂无回复内容