讲解
Symbol 是第七种原始类型,每个 Symbol() 调用都产生一个全局唯一的值,哪怕描述相同:Symbol('id') === Symbol('id') 是 false。它的主要用途是做对象属性键——Symbol 键不会与任何字符串键冲突,也不会出现在 for...in 和 Object.keys 里,适合给对象挂「不打扰别人」的元数据。Symbol.for('key') 是全局注册表版本,同名可取回同一个 Symbol;语言还内置了一批「知名 Symbol」(Symbol.iterator、Symbol.toPrimitive 等)作为扩展协议。
迭代协议是 for...of 背后的机制:一个对象只要有 [Symbol.iterator] 方法,且该方法返回一个「迭代器」(带 next() 方法、next() 返回 { value, done } 的对象),它就是可迭代的,可以被 for...of、展开语法、解构、Array.from 消费。数组、字符串、Map、Set 都内置了这个协议,所以它们都能 for...of;普通对象没有,所以 for...of 对象会报错——先 Object.entries 转数组。
生成器(generator)让自定义迭代变得简单:function* 声明的函数执行后返回一个迭代器,函数体里每次 yield 出一个值、暂停,下次 next 从暂停处继续。给自定义类实现 [Symbol.iterator] 用生成器写只有几行。这是惰性求值、分页拉取、自定义集合类型的基础设施,理解它比会写更重要。
示例
// Symbol:永远唯一
const a = Symbol('id');
const b = Symbol('id');
console.log('相同描述也不同:', a === b);
// Symbol 作属性键:不冲突、不出现在 keys 里
const SECRET = Symbol('secret');
const obj = { name: '公开', [SECRET]: '内部数据' };
console.log('Object.keys 看不到:', Object.keys(obj));
console.log('但能用键取到:', obj[SECRET]);
// 迭代协议手工演示
const arr = ['甲', '乙'];
const it = arr[Symbol.iterator]();
console.log(it.next());
console.log(it.next());
console.log(it.next()); // { value: undefined, done: true }
// 用生成器给自定义类实现迭代
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) yield i;
}
}
console.log('for...of 自定义类:');
for (const n of new Range(1, 5)) {
console.log(n);
}
console.log('展开:', [...new Range(10, 12)]);
// 生成器:惰性斐波那契
function* fib() {
let [x, y] = [0, 1];
while (true) {
yield x;
[x, y] = [y, x + y];
}
}
const gen = fib();
console.log('斐波那契前 8 项:', Array.from({ length: 8 }, () => gen.next().value));
常见坑
- 对普通对象用 for...of:对象不可迭代,直接 TypeError。遍历对象用 Object.entries/keys/values。
- 以为 Symbol 键能 JSON 序列化:JSON.stringify 会丢弃 Symbol 键的属性,跨端传递的数据别用 Symbol 键。
- next() 返回结构记错:迭代器协议返回的是 { value, done } 对象,不是裸值;done 为 true 后 value 通常无意义。
- 生成器函数调用即执行:function* 被调用时函数体一行都不执行,只返回迭代器——很多人以为调用就跑了。执行由 next() 驱动。
小结
Symbol 提供唯一值与「隐身」属性键;迭代协议(Symbol.iterator + next)统一了 for...of、展开、解构;生成器让自定义迭代几行搞定。下一节学习代码组织:模块化。