3、ES6核心语法:let/const、解构赋值、模板字符串、箭头函数、Symbol、Set/Map

ES6 的发布,说实话,是 JavaScript 发展史上一个里程碑。我到现在还记得刚接触那会儿,看到 letconst 时的兴奋感——终于不用再被 var 的变量提升折磨了。这一章,咱们就把 ES6 里最核心、最常用的几个语法点过一遍。这些都是我每天写代码都会用到的东西,你吃透了它们,写出来的代码会干净很多。

3.1 let 与 const:告别 var 的混乱

我个人习惯,现在写代码基本不用 var 了。能用 const 就用 const,确定要重新赋值的才用 let。为什么?因为这样能减少很多意想不到的 bug。

letconst 有两个核心特性:块级作用域暂时性死区

  • 块级作用域:说白了,就是花括号 {} 内部就是一个独立的作用域。变量只在当前块内有效。
  • 暂时性死区:在变量声明之前,你不能访问它。否则会报 ReferenceError
// 以前用 var 的坑
for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100); // 输出 5 个 5
}

// 用 let 就正常了
for (let j = 0; j < 5; j++) {
  setTimeout(() => console.log(j), 100); // 输出 0, 1, 2, 3, 4
}
我的建议:默认用 const。只有当你明确知道这个变量需要重新赋值时,才改用 let。这能帮你写出更可预测的代码。
注意:const 保证的是变量指向的内存地址不变,而不是值不可变。对于对象和数组,你仍然可以修改它们的属性或元素。

3.2 解构赋值:从数组和对象中快速提取数据

解构赋值,说白了就是一种「模式匹配」。它让你能从数组或对象中快速提取数据,赋值给变量。我在项目中经常用它来处理 API 返回的数据,非常方便。

// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first);  // 1
console.log(rest);   // [3, 4, 5]

// 对象解构
const user = { name: '张三', age: 30, email: 'zhangsan@example.com' };
const { name, email } = user;
console.log(name);   // 张三

// 嵌套解构
const data = { person: { address: { city: '北京' } } };
const { person: { address: { city } } } = data;
console.log(city);   // 北京

你想想看,如果没有解构赋值,你得写多少行 const name = user.name 这样的代码?解构赋值让代码变得简洁多了。

实用技巧:解构时还可以设置默认值。比如 const { name = '匿名' } = user,当 user.nameundefined 时,name 就会取默认值。

3.3 模板字符串:告别字符串拼接

以前拼接字符串,得用加号 +,写起来又丑又容易出错。模板字符串用反引号 ` 包裹,用 ${} 嵌入变量或表达式,直观多了。

const name = '李四';
const age = 25;

// 旧方式
const greeting = '你好,' + name + ',你今年' + age + '岁了。';

// 模板字符串
const greetingNew = `你好,${name},你今年${age}岁了。`;

// 还可以写表达式
const info = `明年你${age + 1}岁了。`;

模板字符串还支持多行文本,不用再写 \n 了。我记得有一次写一个复杂的 SQL 查询,用模板字符串直接换行,代码可读性提升了一大截。

3.4 箭头函数:更简洁的函数写法

箭头函数 => 是 ES6 最受欢迎的语法之一。它有两个主要特点:语法简洁不绑定 this

// 传统函数
const add = function(a, b) {
  return a + b;
};

// 箭头函数
const addArrow = (a, b) => a + b;

// 只有一个参数时,可以省略括号
const double = x => x * 2;

// 没有参数时,必须写括号
const sayHello = () => '你好';

箭头函数不绑定 this,它会捕获所在上下文的 this 值。这一点在回调函数中特别有用。

function Timer() {
  this.seconds = 0;
  
  // 传统函数:this 指向 window 或 undefined
  setInterval(function() {
    this.seconds++; // 错误!
  }, 1000);
  
  // 箭头函数:this 指向 Timer 实例
  setInterval(() => {
    this.seconds++; // 正确!
  }, 1000);
}
我曾经踩过的坑:箭头函数不能用作构造函数,也不能用 new 调用。另外,它也没有 arguments 对象。如果你需要这些特性,还是用传统函数吧。

3.5 Symbol:独一无二的值

Symbol 是 ES6 新增的一种原始数据类型。它表示独一无二的值,主要用来解决对象属性名冲突的问题。

const sym1 = Symbol('描述');
const sym2 = Symbol('描述');

console.log(sym1 === sym2); // false,即使描述相同

// 作为对象属性
const obj = {
  [sym1]: '这是 Symbol 属性'
};

console.log(obj[sym1]); // '这是 Symbol 属性'

Symbol 最常见的用途是定义对象的私有属性或常量。比如,你可以用 Symbol 来定义一些内部使用的属性,避免被外部意外覆盖。

小技巧:使用 Symbol.for() 可以创建全局共享的 Symbol。比如 Symbol.for('foo') 会在全局注册表中查找或创建一个 Symbol。

3.6 Set 与 Map:更强大的集合与映射

ES6 之前,JavaScript 只有数组和对象。现在有了 SetMap,处理数据集合方便多了。

Set:不重复的集合

Set 类似于数组,但成员的值都是唯一的,没有重复。

const set = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log(set); // Set { 1, 2, 3, 4, 5 }

// 常用操作
set.add(6);
set.delete(1);
console.log(set.has(2)); // true
console.log(set.size);   // 5

// 数组去重
const arr = [1, 2, 2, 3, 3, 4];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [1, 2, 3, 4]

Map:键值对集合

Map 类似于对象,但它的键可以是任意类型(包括对象、函数等),而且有更丰富的 API。

const map = new Map();

// 设置键值对
map.set('name', '王五');
map.set(123, '数字键');
map.set({ id: 1 }, '对象键');

// 获取值
console.log(map.get('name')); // '王五'

// 遍历
map.forEach((value, key) => {
  console.log(`${key}: ${value}`);
});

// 与对象互转
const obj = Object.fromEntries(map);
const map2 = new Map(Object.entries(obj));

我的经验:在需要频繁增删键值对,或者键不是字符串的场景下,Map 比普通对象更合适。比如缓存数据、存储 DOM 元素与数据的映射关系等。

好了,ES6 的核心语法就这些。说实话,这些特性现在已经是 JavaScript 的标配了。你写 React、Vue 或者 Node.js,几乎天天都会用到它们。多练练,很快就能上手。