ES6变量声明终极指南:告别var,拥抱let和const

0 阅读3分钟

JavaScript 蹭了 Java 的热度,是一种弱类型动态语言,早期设计用来给网页添加交互(幻灯片)和 DOM 编程。
JS 以 ECMAScript(E 为欧洲)为语言标准,ES6 是 JS 的新版本(2015 年发布),让 JS 能够用于企业级大型项目开发。
(注:JS 早期是一个 KPI 项目,有些设计瑕疵。)

1. 声明变量并赋值

  • var(ES5,不推荐使用)
  • let(ES6+,替代 var
  • const(ES6+,声明常量)

2. 作用域(Scope)

2.1 作用域嵌套

  • 全局作用域
  • 函数局部作用域
  • 块级作用域 { ... }

变量属于某个作用域,JS 是弱类型,变量的类型由值决定。

2.2 查找变量的规则(冒泡查找)

  1. 先在当前作用域查找,找到了就使用。
  2. 如果没有找到,向外层作用域查找(冒泡)。
  3. 直到全局作用域都没找到,就报错:ReferenceError: xxx is not defined

2.3 变量的生命周期

函数或代码块执行完毕后,会被垃圾回收,释放内存。变量的声明会在内存中申请区域,销毁时回收。

3. varletconst 的区别

3.1 var 的问题

  • 不支持块级作用域。
  • 没有常量概念,只能靠代码规范约束(例如 var PI = 3.14)。
  • 存在变量提升(hoisting),可能违反直觉。

3.2 let 和 const(支持块级作用域)

  • let:声明变量,值可以改变,类型也可以改变(但不要这么干)。
  • const:声明常量,声明时必须赋值,简单数据类型的值不可改变;复杂数据类型(如对象)的值可以改变,但变量指向的内存地址不能改变。

javascript

const item = 1;
let a; // undefined

// 简单数据类型
const key = 'abc123';
key = 'ABC123'; // ❌ Assignment to constant variable

let points = 50;
points = 51;
points = "52"; // 允许但不推荐

let winner = false;
winner = '戴';

// 复杂数据类型:对象
const person = {
    name: '张三',
    age: 18
};
person.age++; // ✅ 允许修改对象属性
person = "111"; // ❌ 不能重新赋值

4. for 循环中的 var 与 let + setTimeout

4.1 使用 var(不支持块级作用域)

循环变量 i 只有一个(函数作用域或全局),循环结束后 i 变成 10。
所有 setTimeout 回调都引用同一个 i,因此打印的都是 10。

javascript

for (var i = 0; i < 10; i++) {
    console.log(i); // 立即输出 0..9
    setTimeout(function() {
        console.log(`The number is ${i}`); // 一秒后全部输出 10
    }, 1000);
}

4.2 使用 let(支持块级作用域)

每次迭代都会创建一个独立的块级作用域,每个 i 都被单独保存。
setTimeout 回调引用各自作用域中的 i,因此打印 0..9。

javascript

for (let i = 0; i < 10; i++) {
    console.log(i);
    setTimeout(function() {
        console.log(`The number is ${i}`); // 一秒后依次输出 0..9
    }, 1000);
}

5. 变量提升(Hoisting)

  • 代码执行分为两个阶段:编译阶段 和 执行阶段
  • 编译阶段会准备执行上下文(全局执行上下文),此时用 var 声明的变量会被提升,初始值为 undefined
  • 执行阶段才真正赋值。

javascript

console.log(pizza); // ❌ ReferenceError: Cannot access 'pizza' before initialization
let pizza = 'Deep Dish';

注意let 和 const 不支持变量提升,在声明前访问会报错(暂时性死区)。
变量提升是一种容易出错的设计,应避免使用 var,始终使用 let 和 const

6. 代码示例综合

javascript

var height = 200; // 全局作用域

function setwidth() {
    var width = 100; // 局部作用域
    console.log(width, height);
}
setwidth();

var age = 100;
if (age > 12) {
    // 块级作用域
    var dog = age * 7;   // var 不受块级限制,会泄漏到外部
    let x = 111;         // let 只在块内有效
    console.log(dog);
    dog++;
}
console.log(dog);   // 可以访问,输出 701
// console.log(x);  // ❌ x is not defined

// 全局块级作用域
{
    const name = '张三';
    console.log(name);
}
// console.log(name); // ❌ name is not defined

总结

特性varletconst
作用域函数作用域块级块级
变量提升
重复声明允许不允许不允许
必须初始化
值能否改变简单类型不能,复杂类型的属性可以

最佳实践

  • 禁止使用 var
  • 默认使用 const,只有当变量确实需要重新赋值时才使用 let