Symbol 是 JavaScript 中具有唯一性的原始类型,每次调用 Symbol() 都返回全新且不相等的值;其唯一性体现为严格相等和抽象相等均为 false,描述仅用于调试;可用于对象私有属性、全局注册表 Symbol.for() 及内置 Symbol 钩子。

Symbol 是 JavaScript 中一种原始数据类型,它的核心特性是“唯一性”——每次调用 Symbol() 都会返回一个**全新且不相等的值**,即使描述相同,也不会相等。这种唯一性不是靠字符串内容判断,而是由引擎内部保证的底层标识。
Symbol 的唯一性如何体现?
Symbol 的唯一性体现在严格相等(===)和 == 比较中均为 false,哪怕描述(description)完全一样:
const s1 = Symbol('foo');<br>const s2 = Symbol('foo');<br>console.log(s1 === s2); // false<br>console.log(s1 == s2); // false<br>console.log(s1.toString()); // "Symbol(foo)"<br>console.log(s2.toString()); // "Symbol(foo)"
注意:Symbol 描述仅用于调试显示,不影响相等性判断。它也不是“全局唯一”,而是“每次调用必新”——这是与 Symbol.for() 的关键区别。
立即学习“Java免费学习笔记(深入)”;
Symbol 作为对象属性键:避免命名冲突
Symbol 最常见的用途是定义对象的**私有或非覆盖属性**。由于 Symbol 值不会被枚举、不会被 for...in 或 Object.keys() 遍历,且不会与其他属性名冲突,适合做内部标识:
- 给第三方库或插件添加元信息,不污染原有属性
- 在类中定义仅供内部方法使用的“隐藏字段”(虽非真正私有,但可降低误用风险)
- 实现 mixin 或装饰器时,确保注入的属性名不与用户已有属性重名
示例:const INTERNAL_ID = Symbol('id');<br>class User {<br> constructor(name) {<br> this.name = name;<br> this[INTERNAL_ID] = Math.random();<br> }<br> getId() { return this[INTERNAL_ID]; }<br>}<br>const u = new User('Alice');<br>console.log(u[INTERNAL_ID]); // 可访问<br>console.log(Object.keys(u)); // ['name'] —— 不包含 Symbol 键
全局 Symbol 注册表:Symbol.for() 和 Symbol.keyFor()
如果需要跨模块、跨文件共享同一个 Symbol,应使用 Symbol.for(key)。它会在全局注册表中查找已存在的 key,存在则返回,否则新建并登记:
-
Symbol.for('debug')和另一个文件里的Symbol.for('debug')是同一个值 -
Symbol.keyFor(sym)可反查该 Symbol 是否通过for()创建及其 key 名 -
Symbol('debug')永远不会与Symbol.for('debug')相等
适合场景:统一的调试标记、通用的事件类型名、框架级约定键(如 React 的 $$typeof 就是 Symbol)。
内置 Symbol:改变对象行为的“钩子”
JavaScript 预定义了一批以 Symbol. 开头的特殊 Symbol(如 Symbol.iterator、Symbol.toStringTag),它们用于配置对象在特定操作下的行为:
-
[Symbol.iterator]:使对象可被for...of遍历 -
[Symbol.toPrimitive]:控制对象转原始值(如 +、== 时的转换逻辑) -
[Symbol.toStringTag]:影响Object.prototype.toString.call(obj)的输出 -
[Symbol.hasInstance]:自定义instanceof判断逻辑
这些 Symbol 提供了细粒度控制语言内建行为的能力,是实现高级抽象(如自定义迭代器、伪装原生类型)的基础机制。










