什么是Symbol?
** 例子 1:对象“私有属性”隔离(防止外部乱改)**
场景:我们写一个用户模型类 User,需要标记“是否已登录”这个状态,但不想让外部直接改。
// user.js
const _isLogged = Symbol('isLogged');export class User {constructor(name) {this.name = name;this[_isLogged] = false;}login() {this[_isLogged] = true;}isLogged() {return this[_isLogged];}
}
外部使用:
import { User } from './user.js';const u = new User('Tom');
u.login();console.log(u.isLogged()); // trueconsole.log(Object.keys(u)); // ['name'] 看不到 isLogged 状态
u._isLogged = false; // 无效,外部改不了 Symbol 的那个字段
解释:
_isLogged 是一个 Symbol,别人看不见,也拿不到引用。
这样你就能“保护”这个属性,相当于实现了“私有字段”。
⚙️ 例子 2:防止框架/插件字段冲突(在库开发中常见)
场景:假设你写了一个数据追踪库 tracker.js,要在对象里偷偷存一些标记信息。
但怕用户对象里也有同名字段,比如 id、__meta 等。
// tracker.js
const TRACKER_ID = Symbol('trackerId');export function markTracked(obj) {obj[TRACKER_ID] = Date.now();
}export function isTracked(obj) {return !!obj[TRACKER_ID];
}
外部代码:
import { markTracked, isTracked } from './tracker.js';const user = { id: 1, name: 'Tom' };
markTracked(user);console.log(user);
// { id: 1, name: 'Tom' } // 看不出来被标记了console.log(isTracked(user)); // true
意义:
你的库可以安全地在任意对象上打“隐形标记”,
不怕和用户自己的字段重名。
** 例子 3:自定义对象行为(框架内部常用)**
场景:实现一个类,控制它在被转字符串或比较时的表现。
const ID = Symbol('id');class Product {constructor(name, id) {this.name = name;this[ID] = id;}[Symbol.toPrimitive](hint) {if (hint === 'string') return this.name;if (hint === 'number') return this[ID];return this.name;}
}const p = new Product('iPhone', 1001);console.log(`${p}`); // 'iPhone'
console.log(+p); // 1001
在一些框架中(比如 ORM / 数据模型),会用这种方式:
- 让对象在日志打印时显示友好的字符串;
- 但在计算或比较时,自动转成 ID 或主键值。
** Bonus:与** Symbol.for() 结合,用全局共享标识
场景:多个模块都需要共享一个“全局唯一标识”,比如 Redux 中的 action type。
// moduleA.js
export const ACTION_TYPE = Symbol.for('APP_ACTION');// moduleB.js
import { ACTION_TYPE } from './moduleA.js';const action = { type: ACTION_TYPE, payload: 'data' };// 任意地方只要用 Symbol.for('APP_ACTION') 拿到的就是同一个标识
console.log(Symbol.for('APP_ACTION') === ACTION_TYPE); // true
✅ 总结(贴近实战的用途)
用途 | 实际场景 |
---|---|
1️⃣ 隐藏内部属性 | 模拟私有字段(框架、SDK 中常见) |
2️⃣ 防止命名冲突 | 在第三方库或插件中安全打标 |
3️⃣ 自定义对象行为 | 控制 toString()、+、== 的表现 |
4️⃣ 跨模块唯一标识 | 用 Symbol.for() 实现全局共享常量 |
Don’t reinvent the wheel, library code is there to help.
欢迎关注公-众-号【TaonyDaily】、留言、评论,一起学习。