1.var let const的区别

142 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

var let const的区别

在看视频的时候只讲了用var定义变量,之后看书的时候看到了let和const。于是准备写一篇Blog。

var

  1. 在全局作用域用var定义的变量是全局变量,在其所有子级域中都可以使用。

  2. var声明的变量存在变量提升的情况。(var的预解析)

    console.log(f);
    var f = 2;
    console.log(f);
    
    //输出:
    //undefined
    //2
    

    编译器在执行阶段,会先定义变量,再顺序编译执行。

    // var的变量提升涉及到有个预解析的问题,即在代码执行之前,对代码进行通读并解析。
    
    // 1. 解析了var关键字,即变量提升,即先var 声明变量,但不赋值。
    // 2. 解析了声明式函数,即声明一个变量,并定义为函数。但执行代码是按顺序执行的。 
    // 3. 不管if语句中的条件如何,if语句中的代码依旧会预解析。
    // 4. 函数中return语句后面的var也会预解析。
    // 5. 预解析中重名以函数为主
    
    console.log(a);  //输出为 undefined
    var a = 100;
    console.log(a);  //输出为 100
    
    if(false){
        var b = 200;
    }
    console.log(b);  //输出为 undefined 
    
    function f(){
        console.log('执行函数f()'); 
        console.log(c);
        return ;
        var c = 200;  //输出为 undefined 
    }
    f();
    console.log(c);  //会报错
    
  3. var可以重复声明一个变量。

    var a = 1;
    console.log(a);
    var a = 2;
    console.log(a);
    var a = 3;
    console.log(a);
    
    // 输出
    // 1
    // 2
    // 3
    
  4. 在函数内用var声明的变量是局部变量

    如果函数作用域有该变量,则给自己赋值,如果没有则会给父级的变量赋值。如果全局变量都没有,则会定义一个全局变量并赋值

    //在函数作用域用var声明变量是局部变量,在父级作用域是未声明
    function f(){
        var a = 1;
    }
    f();
    console.log(a);
    
    // 会报错
    
    //并不会影响父级作用域中a的值
    var a = 2;
    function f1(){
        var a = 1;
    }
    f1();
    console.log(a);
    
    // 输出结果2
    
    //函数作用域没有该变量,所以会给父级作用域的变量a赋值
    var a = 2;
    function f2(){
        a = 1;
    }
    f2()
    console.log(a);
    
    // 输出结果1
    
    //全局作用域也没有变量a,所以会声明一个全局变量a
    function f3(){
        a = 1;
    }
    f3()
    console.log(a);
    
    // 输出结果1
    

let

  1. let是ES6新增的语法。用法类似于var,但声明的变量只在let所在的代码块内生效。

    for(var i = 1;i < 10;i++){}
    console.log(i);
    //可以正确输出i的值,即 10
    for(let j = 1;j < 10;j++){}
    console.log(j);
    //会报错
    
  2. 不存在变量提升,在用let声明一个变量前,这个变量是不存在的,如果引用就会报错。

  3. 暂时性死区

    当代码块用let声明一个变量时,在在该代码块中在let声明变量之前,该变量都不可用。

    造成该错误的主要原因是:ES6新增的let、const关键字声明的变量会产生块级作用域,如果变量在当前作用域中被创建之前被创建出来,由于此时还未完成语法绑定,如果我们访问或使用该变量,就会产生暂时性死区的问题,由此我们可以得知,从变量的创建到语法绑定之间这一段空间,我们就可以理解为'暂时性死区'

    var a = 111;
    if(1){
        console.log(a);
        a = 123;
        let a;
        console.log(a);
    }
    
  4. 不能再相同作用域重复声明,但可以在不同代码块中重复声明

    let a = 1;
    {
        let a = 2;
        console.log(a);
    }
    console.log(a);
    
    //会依次输出2 1
    
    let b = 1;
    
        let b = 2;
        console.log(b);
    
    console.log(b);
    
    //会报错
    

    所以不能在函数内重新声明形参。

const

  1. const声明一个只读的变量,一旦声明,该变量的值不能改变。可以当做常量。而且const声明变量必须立即初始化,不然也会报错。

    const a = 1;
    a = 2;
    
    //会报错
    
  2. 用const声明已经声明的变量也会报错。

    let a = 1;
    var b = 1;
    const a = 2;
    const b = 2;
    

实际上const是保证变量指向内存地址的值是不能改动的,可以对简单数据类型,是可以当做常量的。

而对于复杂类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,即实际数据的位置不变,但不能保证实际数据不被修改。

var a = 2;
const f = {a}
console.log(f);
f.a = 1;
f.b = 3;
console.log(f);

//输出为:
//{ a: 2 }
//{ a: 1, b: 3 }

其他情况,const与let是一致的。

总结

var,let,const的区别主要为以下几点:

  • 变量提升

    var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined。

    let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错。

  • 暂时性死区

    var不存在暂时性死区。

    let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

  • 块级作用域

    var不存在块级作用域。

    let和const存在块级作用域。

  • 重复声明

    var允许重复声明变量。

    let和const在同一作用域不允许重复声明变量。

  • 修改声明的变量

    var和let可以。

    const声明一个只读的常量。一旦声明,常量的值就不能改变。复杂数据类型的值和结构仍然可以修改。