Symbol 是 JavaScript 中唯一能保证值唯一性的原始类型,每次调用 Symbol() 都返回全新不相等的值,其唯一性由引擎内部私有标识保障,不可枚举且防冲突,但 JSON.stringify 会忽略、不可点访问、类中不能 static 声明。
Symbol 是 JavaScript 中唯一能保证值唯一性的原始类型,专门用来生成不可被枚举、不可被意外覆盖的对象键。
每次调用 Symbol() 都返回一个全新且不相等的值,即使描述相同:
const a = Symbol('foo');
const b = Symbol('foo');
console.log(a === b); // false这种唯一性不是靠字符串内容,而是引擎内部维护的私有标识。它不像 Symbol.for('foo') 那样会全局复用,所以普通 Symbol() 天然适合做“防冲突”的私有属性名。
Symbol 键不会出现在 for...in、Object.keys()、Object.getOwnPropertyNames() 中,但可通过 Object.getOwnPropertySymbols() 显式获取:
const sym = Symbol('id');
const obj = { [sym]: 123, name: 'alice' };
console.log(Object.keys(obj)); // ['name']
console.log(Object.getOwnPropertyNames(obj)); // ['name']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(id)]这意味着你可以在不污染对象公共接口的前提下,挂载元数据或内部状态。
常见用途包括:缓存计算结果、标记对象类型、避免第三方库属性名冲突;但要注意几个关键限制:
JSON.stringify() 会直接忽略 Symbol 键,序列化后丢失obj.sym 不行,必须用方括号 obj[sym]
static [sym] = ... 定义静态 Symbol 属性(需在类外赋值)如果你需要跨模块共享某个 Symbol,必须用 Symbol.for(key) 注册到全局符号注册表,否则不同模块调用 Symbol('x') 得到的仍是不同值。
Symbol 的设计初衷不是替代私有字段(如 #field),而是提供一种可控的、可反
射的“隐藏但非完全私有”的键机制——它的“唯一性”和“不可枚举性”是硬保障,但“是否可见”取决于你用什么 API 去查。这点容易被低估。