• var 、let 和 const 的区别


    • var 声明的范围是函数作用域,let 和 const 声明的范围是块作用域

    • var 声明的变量会被提升到函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征

    • var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许

    • 在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会

    • const 的行为与 let 基本相同,唯一 一个重要的区别是,使用 const 声明的变量必须进行初始化,且不能被修改

    关键字

    变量提升

    块级作用域

    重复声明同名变量

    重新赋值

    var

    ×

    let

    ×

    ×

    const

    ×

    ×

    ×

    1.作用域

    **var**没有块级作用域,而**let声明的范围是块作用域;**一对大括号 就是 一个块级作用域

    if (true) {
        var message = "hello";
        console.log(message); // hello
    }
    console.log(message); // hello
    
    
    if (true) {
        let message = "hello";
        console.log(message); // hello
    }
    console.log(message); // error: message is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    let不允许同一个块作用域中出现冗余声明

    if (true) { 
        // error: 无法重新声明块范围变量“a”
        let a;
        let a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    JS 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标识符不会报错,这是因为同一个块中没有重复声明:

    let a = 666;
    console.log(a); // 666
    if (true) {
        let a = '啊哈哈';
        console.log(a); // 啊哈哈
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    **varlet声明的并不是不同类型的变量,它们只是指出变量在相关作用域如何存在,所以对声明冗余报错不会因混用varlet**而受影响:

    // error
    var a;
    let a;
    
    // error
    let b;
    var b;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.变量提升

    //用var命名的变量有变量提升
    console.log(num1);  // undefined
    var num1 = 10;
    // 以上代码运行时,相当于下面的写法
    ?
    var num2;  // 声明提升到作用域最顶端
    console.log(num2);  // undefined
    num = 10;
    /*****************************************/
    //用 let 或 const 命名的变量有变量提升
    console.log(num3); // Uncaught ReferenceError: num3 is not defined
    let num3 = 10;      
    ?
    console.log(num4); // Uncaught ReferenceError: num4 is not defined
    const num4 = 10;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.暂时性死区

    只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量

    var tmp = 123; // 声明
    if (true) {
      tmp = 'abc'; // 报错 因为本区域有tmp声明变量
      let tmp; // 绑定if这个块级的作用域 不能出现tmp变量
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    **暂时性死区和不能变量提升的意义在于:**为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。

    4.重复声明同名变量和重新赋值

    //var 关键字可以声明同名变量,实际第二次声明是对第一次声明的变量重新赋值
    var num1 = 10;
    var num1 = 20;
    console.log(num1);  // 20
    ?
    //let 和const 关键字不能重复声明同名变量,即使之前是用var声明的也会报错
    var num2 = 10;
    let num2 = 20;  // Uncaught SyntaxError: Identifier 'num2' has already been declared 
    ?
    //let 和 var 在声明变量时,可以不用初始化
    let num3;  
    console.log(num3);  // undefined
    var num4;  
    console.log(num4);  // undefined
    ?
    //const 声明常量时必须初始化,因为 `const` 关键字声明的是常量,声明后不能再赋值
    const num5;  // Uncaught SyntaxError: Missing initializer in const declaration
    ?
    
    //let 声明的变量可以重新赋值
    let num1 = 10;
    num1 = 20;
    console.log(num1);  // 20
    //const 只能在声明时赋值,之后不能再重新赋值
    const num2 = 10;
    num2 = 20;  // Uncaught TypeError: Assignment to constant variable.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    5.扩展

    5.1.全局声明

    使用var在全局作用域中声明的变量会成为window对象的属性,letconst声明的变量则不会:

    var a = 666;
    console.log(window.a); // 666
    
    let b = 666;
    console.log(window.b); // undefined
    
    const c = 666;
    console.log(window.c); // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.2.for 循环中的var和let 声明的区别

    for (var i = 0; i < 5; i++) {
        setTimeout( () => {
            console.log(i); // 5、5、5、5、5
        }, 0 )
    }
    
    for (let i = 0; i < 5; i++) {
        setTimeout( () => {
            console.log(i); // 0、1、2、3、4
        }, 0 )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    var是因为在退出循环时,迭代变量保存的是导致循环退出的值,也就是 5。在之后异步执行超时逻辑时,所有的i都是同一个变量,因此输出的都是同一个最终值。

    而在使用let声明迭代变量时,JS 引擎在后台会为每个迭代循环声明一个新的迭代变量,每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    Maven——分模块开发与设计(重点)
    美团一面:为什么线程崩溃崩溃不会导致 JVM 崩溃
    代码随想录 Leetcode435. 无重叠区间
    5、Kafka海量日志收集系统架构设计
    in用不用索引,啥时候能用啥时候不能用,一文说清
    sql实例-2
    Unity 保存图片到相册以及权限管理
    redhat 新开启一个ssh端口
    基于暗原色先验的单幅图像去雾——算法复现
    基于HTML+CSS+JavaScript+Bootstarp响应式健身网站(web前端期末大作业)
  • 原文地址:https://blog.csdn.net/embelfe_segge/article/details/126080376