标准答案
- Symbol 是一种原始类型,用 Symbol() 创建的值是唯一的。即使描述相同,两个 Symbol 也不相等。
- Symbol 常用作对象属性键,减少和普通字符串属性名冲突的风险,也可以保存不希望被常规枚举看到的内部字段。
- Symbol.for 会使用全局注册表。相同 key 会拿到同一个 Symbol,适合跨模块共享约定;Symbol() 每次都会创建全新的唯一值。
- 内置 Symbol 用来定制语言协议。Symbol.iterator 定义可迭代行为,Symbol.toStringTag 影响 Object.prototype.toString,Symbol.toPrimitive 定义对象转原始值,Symbol.hasInstance 可以定制 instanceof。
题目解析
Symbol 的价值有两层:一层是唯一属性键,另一层是语言协议入口。只说“唯一值”会漏掉 for...of、类型标签和类型转换这些常见用法。
Symbol 属性不是绝对私有。Object.keys、for...in、JSON.stringify 默认看不到 Symbol 键,但 Object.getOwnPropertySymbols 和 Reflect.ownKeys 可以拿到。
Symbol.for 适合全局共享标识,但它也意味着 key 会进入全局注册表。只需要局部唯一值时,用 Symbol() 更清楚。
代码示例
下面示例展示 Symbol 属性键、全局注册表和 Symbol.iterator 协议。
JavaScript
const localId = Symbol('id')
const anotherLocalId = Symbol('id')
localId === anotherLocalId // false
const sharedA = Symbol.for('app.user')
const sharedB = Symbol.for('app.user')
sharedA === sharedB // true
const user = {
name: 'Alice',
[localId]: 1001
}
Object.keys(user) // ['name']
Reflect.ownKeys(user) // ['name', Symbol(id)]
const range = {
start: 1,
end: 3,
*[Symbol.iterator]() {
for (let value = this.start; value <= this.end; value += 1) {
yield value
}
}
}
[...range] // [1, 2, 3]常见误区
- 误以为 Symbol 属性完全私有。它只是默认枚举不容易看到。
- 混淆 Symbol() 和 Symbol.for()。
- 忘记 Symbol 是原始类型,不是对象。