ES6变量声明大作战:let/const是如何吊打var的?

54 阅读4分钟

一、从"变量界的老油条"说起

在ES6出现之前,JavaScript世界里只有一个声明变量的关键字——var。这货就像个"老油条",自由散漫得让人头疼:

  • 可以在任何地方声明,随时随地"提升"自己的存在感
  • 在全局作用域里声明,就敢往window对象上凑近乎
  • 同一个变量名,想声明几次就声明几次,完全不把规则放在眼里
  • 没有块级作用域的概念,在哪里都能"蹦跶"

直到有一天,ES6带来了两个"新青年"——letconst,它们决定要好好整顿一下变量界的风气!

二、let/const的四大"家规",彻底治住了var的"野"性

1. 拒绝"声明提升",做事要有先后顺序

var就像个急性子,不管你在哪里写了var a = 1,它都会偷偷跑到作用域顶部先占个位子。结果就是:

console.log(age); // undefined(不是报错,而是undefined!)
var age = 18;

// 实际上JavaScript会解释成:
var age;
console.log(age);
age = 18;

letconst就守规矩多了:

console.log(age); // 直接报错:Cannot access 'age' before initialization
let age = 18;

这就像你不能提前使用还没买的东西一样,合情合理!

2. 不当"window"的"跟屁虫",保持独立人格

var在全局作用域声明时,会自动成为window对象的属性,就像个"跟屁虫":

var globalVar = '我是全局变量';
console.log(window.globalVar); // '我是全局变量'

letconst就有独立人格,即使在全局声明也不会依附于window

let globalLet = '我也是全局变量';
console.log(window.globalLet); // undefined

3. 拒绝"重复声明",专情到底

var就像个花心大萝卜,同一个变量名可以声明多次:

var age = 18;
var age = 20; // 不报错,age变成20
console.log(age); // 20

letconst就专情多了,一旦认定了一个变量名,就不允许再变:

let age = 18;
let age = 20; // 直接报错:Identifier 'age' has already been declared

4. 支持"块级作用域",该在哪里就在哪里

var没有块级作用域的概念,只要出现在同一个函数里,就到处乱跑:

{  
  var myname = '康总';
}
console.log(myname); // '康总'(从块里跑出来了!)

letconst就规矩多了,待在块级作用域里乖乖不出来:

{  
  let age = 19;
  var myname = '康总';
}
console.log(age); // 报错:age is not defined
console.log(myname); // '康总'

这个特性在循环中特别有用,解决了经典的"循环变量泄漏"问题:

for (let i = 0; i < 10; i++) {  
  setTimeout(() => console.log(i), 0); // 依次输出0-9
}

for (var i = 0; i < 10; i++) {  
  setTimeout(() => console.log(i), 0); // 输出10个10
}

三、变量解构赋值:JavaScript界的"拆箱大师"

ES6不仅带来了letconst,还带来了一个"拆箱大师"——变量解构赋值。它能让你更优雅地从数组或对象中提取数据。

1. 数组解构:就像"按顺序领快递"

// 传统方式
let a = 1, b = 2, c = 3;

// 解构赋值方式
let [a, b, c] = [1, 2, 3];

// 还支持嵌套解构
const arr = [1, [2, 3, [4], 5]];
let [a, [b, c, [d], e]] = arr;
console.log(a, b, c, d, e); // 1 2 3 4 5

// 剩余参数
const arr = [1, 2, 3, 4, 5];
let [a, ...b] = arr;
console.log(a, b); // 1 [2, 3, 4, 5]

2. 对象解构:就像"按名字领快递"

const obj = {
  name: '康总',
  age: 18,
  like: {
    n: '泡脚'
  }
};

// 传统方式
let name = obj.name;

// 解构赋值方式
let {name, age, like: {n}} = obj;
console.log(name, age, n); // '康总' 18 '泡脚'

3. 字符串解构:连字符串都能拆

const [a, b, c, d, e] = 'hello';
console.log(a, b, c, d, e); // 'h' 'e' 'l' 'l' 'o'

// 还能解构字符串的属性
let {length} = 'hello';
console.log(length); // 5

4. 函数参数解构:让函数调用更优雅

function foo({x: a, y: b}) {
  return a + b;
}

foo({x: 1, y: 2}); // 3

四、let和const,该怎么选?

letconst都是ES6的"新青年",那我们该怎么选择呢?

  • 如果你声明的变量值可能会变,用let
  • 如果你声明的变量值不会变,用const(更安全,推荐优先使用)

const虽然叫"常量",但只是保证指针不变,对于对象和数组,里面的内容还是可以变的:

const person = {name: '康总'};
person.name = '康少'; // 可以修改
person = {}; // 报错:Assignment to constant variable.

五、总结:为什么说let/const是var的"升级版"?

  1. 更安全:拒绝声明提升,避免了变量未定义就使用的问题
  2. 更规范:不允许重复声明,保持代码的整洁
  3. 更灵活:支持块级作用域,让变量的作用范围更清晰
  4. 更独立:不在全局作用域污染window对象

而变量解构赋值则让我们的代码更简洁、更易读,特别是在处理复杂数据结构时。

现在,你应该明白为什么在现代JavaScript开发中,我们都推荐使用letconst,而尽量避免使用var了吧?下次写代码时,不妨试试这些ES6带来的新特性,相信你会爱上它们的!

(偷偷告诉你:使用let和const,还能减少80%的变量相关bug哦!)