Symbol 创建的属性名天然避免命名冲突,需定义一次并复用;WeakMap 可实现更强隔离与自动内存清理;慎用 Symbol.for() 防全局污染;闭包封装可彻底隐藏 Symbol 变量。
用 symbol 创建属性名,能天然避开命名冲突和第三方库的覆盖风险,因为每个 symbol 值都是唯一、不可枚举、不可遍历的——哪怕第三方库调用 for...in、object.keys()、json.stringify(),甚至 object.getownpropertynames(),都拿不到它。
每次调用 Symbol('id') 都会生成一个全新值,无法用于后续访问。真正实用的方式是:定义一次、导出复用。
export const internalId = Symbol('internalId');
obj[internalId] = 123;
obj[internalId] —— 这样才能命中obj[Symbol('internalId')],那会创建新 Symbol,永远读不到原值仅靠 Symbol 键仍可通过 Object.getOwnPropertySymbols(obj) 暴露出来。若需更强隔离(比如防止调试时被意外发现),就该用 WeakMap。
const privateStore = new WeakMap();
privateStore.set(obj, { token: 'abc', expires: Date.now() });
privateStore.get(obj)?.token;
Symbol.for('auth') 会在全局注册表中查找或创建同名 Symbol,适合跨模块通信,但容易引发意外交互。
Symbol.for('cache'),拿到的是同一个 Symbol —— 看似方便,实则可能被其他库无意覆盖Symbol.keyFor(sym) 查它是否已注册;未注册的局部 Symbol 返回 undefined
Symbol(),更安全可控即使用了 Symbol,如果把 const _id = Symbol() 直接暴露在模块顶层,别人仍可能通过 import { _id } from './utils.js' 拿到它。真要模拟“私有”,就得封进闭包。
setId()、getId()),内部用闭包持有的 Symbol 访问属性Object.getOwnPropertySymbols() 查到的 Symbol,外部也无法复用 —— 因为变量名根本不可见