ES6-let-ver

let 和 var 的作用区别总结

根据阮一峰《ECMAScript 6 入门教程》及相关资料,以下是 letvar 的核心区别总结:

1. 作用域规则

  • let

    • 块级作用域:仅在声明它的代码块({})内有效,包括 ifforwhile 等语句。
    • 示例
      {
        let a = 1;
        var b = 2;
      }
      console.log(a); // 报错:a 未定义
      console.log(b); // 输出 2(var 变量泄漏到外部)
  • var

    • 函数级作用域:变量在声明它的函数或全局作用域内有效,无视代码块。
    • 示例
      if (true) {
        var x = 5;
      }
      console.log(x); // 输出 5(var 穿透块级作用域)

2. 变量提升(Hoisting)

  • let

    • 无变量提升:声明前访问会触发 暂时性死区(TDZ),直接报错。
    • 示例
      console.log(c); // 报错:c 未初始化
      let c = 3;
  • var

    • 存在变量提升:声明前访问值为 undefined,不会报错。
    • 示例
      console.log(d); // 输出 undefined
      var d = 4;

3. 重复声明

  • let

    • 禁止重复声明:同一作用域内重复声明同一变量会报错。
    • 示例
      let e = 10;
      let e = 20; // 报错:重复声明
  • var

    • 允许重复声明:后声明的变量会覆盖之前的值。
    • 示例
      var f = 100;
      var f = 200; // 正常执行,f 最终为 200

4. 全局对象属性

  • let

    • 不绑定到全局对象:声明的全局变量不会成为 window(浏览器)或 global(Node.js)的属性。
    • 示例
      let g = 1000;
      console.log(window.g); // 输出 undefined(浏览器中)
  • var

    • 绑定到全局对象:声明的全局变量会成为全局对象的属性。
    • 示例
      var h = 2000;
      console.log(window.h); // 输出 2000(浏览器中)

5. 循环中的行为差异

  • let

    • 独立作用域:每次迭代会创建独立的变量环境,适合闭包场景。
    • 示例
      for (let i = 0; i < 3; i++) {
        setTimeout(() => console.log(i)); // 分别输出 0、1、2
      }
  • var

    • 共享作用域:所有迭代共享同一变量,闭包中可能捕获意外值。
    • 示例
      for (var j = 0; j < 3; j++) {
        setTimeout(() => console.log(j)); // 全部输出 3
      }

总结表格

特性 let var
作用域 块级作用域 函数级作用域
变量提升 无(TDZ 报错) 有(值为 undefined
重复声明 禁止 允许
全局对象属性 不绑定 绑定
循环行为 独立作用域(适合闭包) 共享作用域(可能意外值)

延伸:constlet 的区别

  • const 声明的是常量,不可重新赋值,但非简单类型(如对象)的属性可修改。
  • const 同样具有块级作用域、无变量提升、禁止重复声明等特性。
  • 示例
    const PI = 3.14;
    PI = 3.14159; // 报错:常量不可重新赋值
    
    const obj = { a: 1 };
    obj.a = 2; // 正常执行(修改属性)
    obj = {}; // 报错:常量不可重新赋值