Symbol 是 JavaScript 中唯一能创建真正唯一值的原始类型,用于对象属性可避免覆盖和枚举,适合内部标记、私有状态及规避命名冲突;Symbol.for() 实现跨模块共享,WeakMap 配合 Symbol 可增强私有性。

Symbol 是 JavaScript 中唯一能创建真正唯一值的原始类型,用它给对象添加属性,可以确保该属性不会被意外覆盖或枚举,特别适合做内部标记、私有状态或避免第三方库命名冲突。
用 Symbol 创建不可枚举的内部标记
Symbol 值每次调用 Symbol() 都会生成一个全新且唯一的值,即使描述相同,它们也不相等。这使它天然适合作为对象的“隐藏”键:
- 该属性不会出现在
for...in、Object.keys()、JSON.stringify()中 - 不会被
Object.assign()或展开运算符({...obj})复制 - 仍可通过
Object.getOwnPropertySymbols()或直接访问获取
示例:
const internalId = Symbol('id');
const user = { name: 'Alice' };
user[internalId] = 123;
console.log(user[internalId]); // 123
console.log(Object.keys(user)); // ['name']
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]
用 Symbol.for() 实现跨模块共享标记
若多个文件或第三方库需识别同一类内部标记(比如都检查某个“是否已初始化”状态),可使用 Symbol.for(key)。它会在全局符号注册表中查找或创建同名 Symbol,保证返回同一个值:
-
Symbol.for('initialized')在任意地方调用都返回相同 Symbol - 与
Symbol('initialized')完全不同——后者每次都是新值 - 适合框架/插件约定的通用标记,如
Symbol.for('react.element')就是 React 内部使用的
注意:key 是字符串,建议加命名空间前缀(如 'mylib:isFrozen')降低冲突风险。
结合 WeakMap 实现真正的私有状态
仅靠 Symbol 属性仍可通过 getOwnPropertySymbols 暴露。如需更强封装,推荐搭配 WeakMap:
- WeakMap 的键必须是对象,值可任意;它不阻止垃圾回收,适合存实例私有数据
- Symbol 可作为 WeakMap 的 key(但非必需),更常见的是用 Symbol 命名 WeakMap 实例本身
- 外部无法访问 WeakMap,除非你主动暴露其引用
示例:
const _cache = new WeakMap();
const _state = Symbol('state');
class CacheManager {
constructor() {
_cache.set(this, { [__state]: 'idle' });
}
getState() {
return _cache.get(this)[_state];
}
}
规避第三方库冲突的实际建议
在开发工具库或插件时,不要依赖固定字符串键(如 obj.__isProcessed),改用 Symbol:
- 用
Symbol('mylib:processed')替代'__isProcessed' - 若需调试,可用描述字符串(如
'mylib:processed'),它只用于调试显示,不影响唯一性 - 避免使用
Symbol.iterator等内置 Symbol,除非你真在实现对应协议 - 对公开 API,仍应提供字符串形式的配置项或方法,Symbol 仅用于内部逻辑

















