跳到主要内容

Symbol 是什么,有什么作用?

面试速答(30 秒版 TL;DR)

  • Symbol 是一种原始类型(primitive),每个 Symbol() 值都“保证唯一”。
  • 主要用途是做对象的唯一属性键,避免命名冲突(尤其是库代码、框架扩展点)。
  • 还有一类“内置/知名 Symbol(well-known symbols)”用于定制语言行为,例如 Symbol.iterator 让对象可迭代。

为什么需要 Symbol?

对象属性名传统上只有字符串,这会带来两个问题:

  • 不同模块/库可能用同一个字符串 key,容易冲突覆盖。
  • 想做“内部私有标记”时,字符串 key 很容易被误用或被枚举出来。

Symbol 作为 key 的价值:几乎不可能“撞名”,更适合做扩展点或内部标记。


最小例子:用 Symbol 做“不会冲突的 key”

const internalId = Symbol('internalId');

const user = {
name: 'Alice',
[internalId]: 42,
};

console.log(user[internalId]); // 42
console.log(Object.keys(user)); // ["name"],Symbol key 不会出现在这里
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(internalId)]

要点:Symbol 属性默认不会被 Object.keys / for...in 枚举到,但它并不是“安全私有”,只是降低误用。


重点:Symbol.iterator 与可迭代协议

当对象实现了 obj[Symbol.iterator]() 并返回一个 iterator,它就能被 for...of、展开运算符 ...Array.from 等消费。

const iterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let i = 0;
return {
next: () => {
if (i >= this.data.length) return {done: true, value: undefined};
return {done: false, value: this.data[i++]};
},
};
},
};

console.log([...iterable]); // [1, 2, 3]

常见追问

  • Symbol.for(key):从全局注册表取同一个 symbol(跨文件/模块共享)。Symbol(key) 则总是创建新值。
  • JSON.stringify:会忽略 Symbol 值与 Symbol key(常见踩坑点)。

易错点/坑

  • 把 Symbol 当成“真正私有”:它只是不可轻易枚举,但仍可通过 getOwnPropertySymbols 取到。
  • Symbol.forSymbol() 混淆:一个“全局复用”,一个“永远唯一”。

速记要点(可背诵)

  • Symbol:唯一的 primitive,常用来做“不会冲突的对象属性 key”。
  • well-known symbols:用来定制语言行为,Symbol.iterator 最常考。