Symbol值天然唯一,Symbol('a')与Symbol('a')不相等;Symbol.for('key')可跨上下文共享同一Symbol;Symbol用作对象键时不可被常规遍历方法访问。

Symbol 类型创建的值天然唯一,哪怕描述相同,Symbol('a') 和 Symbol('a') 也不相等 —— 这是它最核心的特性,不是“模拟唯一”,而是语言层保证。
用 Symbol() 创建基础唯一值
每次调用 Symbol()(无论带不带参数)都返回一个全新、不可复现的值:
const a = Symbol('id');
const b = Symbol('id');
console.log(a === b); // false
console.log(typeof a); // "symbol"
参数(如 'id')仅作描述,不影响唯一性,也不参与比较。调试时能在控制台看到这个描述,但代码里不能靠它识别 Symbol。
- 不传参:
Symbol()也是合法的,描述为undefined - 参数建议用字符串,其他类型会强制转字符串(
Symbol(42)等价于Symbol('42')) - 不能用
new Symbol(),会报TypeError: Symbol is not a constructor
用 Symbol.for() 创建全局登记的 Symbol
当需要跨模块、跨执行上下文“共享同一个 Symbol”时,用 Symbol.for(key)。它会先在全局 Symbol 注册表中查找,存在就返回,否则新建并登记:
立即学习“Java免费学习笔记(深入)”;
const s1 = Symbol.for('debug');
const s2 = Symbol.for('debug');
console.log(s1 === s2); // true
注意:Symbol.for('x') 和 Symbol('x') 完全不同,前者可被复用,后者永远唯一。
- 键名(
key)必须是字符串,否则抛错 - 注册表是全局的,所有代码共享,命名要谨慎避免冲突
- 可用
Symbol.keyFor(sym)反查某个 Symbol 是否登记过、登记的键是什么
Symbol 作为对象属性键的注意事项
Symbol 最常用场景是定义“不会被遍历到、不易被意外覆盖”的属性:
-
Object.keys()、for...in、JSON.stringify()都忽略 Symbol 键 - 要用
Object.getOwnPropertySymbols()或Reflect.ownKeys()才能拿到 - 赋值写法:
obj[mySym] = 'hidden',不能用点号obj.mySym - 若想让 Symbol 属性可枚举,需显式设置
enumerable: true(默认false)
常见陷阱:用 Symbol.iterator 实现自定义迭代器时,必须确保它是全局内置 Symbol,而不是自己 Symbol('iterator') —— 否则 for...of 不认。
哪些 Symbol 是内置的?怎么用?
ES6+ 预定义了一批以 Symbol. 开头的全局 Symbol,用于定制对象行为,比如:
-
Symbol.iterator:让对象支持for...of -
Symbol.toStringTag:影响Object.prototype.toString.call(obj)的输出 -
Symbol.hasInstance:影响instanceof判断逻辑 -
Symbol.toPrimitive:控制对象转原始值(如 +obj、`${obj}`)
这些都不能重写或覆盖,只能在对象上定义对应方法来响应。例如实现 Symbol.iterator,必须把它作为属性键挂到对象上,且值是一个返回迭代器的函数。
真正容易被忽略的是:Symbol 本身不能被 JSON 序列化,也不能直接 console.log 输出完整结构(只显示描述),调试时如果依赖打印看 Symbol 属性,得手动提取或用 Object.getOwnPropertySymbols() 辅助检查。










