JavaScript 中的 Symbol
Symbol 是 ES6 引入的一种原始数据类型,表示独一无二的值。
基本特性
1. 唯一性
javascript
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false
// 即使描述相同,也不相等
const s3 = Symbol('id');
const s4 = Symbol('id');
console.log(s3 === s4); // false
2. 不能与 new 一起使用
javascript
const s = Symbol(); // ✅ 正确
const s2 = new Symbol(); // ❌ TypeError: Symbol is not a constructor
创建 Symbol
javascript
// 无描述
const sym = Symbol();
// 带描述(便于调试)
const symWithDesc = Symbol('mySymbol');
console.log(symWithDesc.toString()); // "Symbol(mySymbol)"
console.log(symWithDesc.description); // "mySymbol" (ES2019)
主要用途
1. 作为对象属性名(防止冲突)
javascript
const id = Symbol('id');
const user = {
name: '张三',
[id]: 12345, // 使用计算属性名
age: 25
};
console.log(user[id]); // 12345
console.log(Object.keys(user)); // ['name', 'age'] - Symbol 属性不显示
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]
2. 定义常量(避免重复)
javascript
// 传统方式(可能冲突)
const COLORS = {
RED: 'RED',
GREEN: 'GREEN',
BLUE: 'BLUE'
};
// Symbol 方式(绝对唯一)
const COLORS_SYMBOL = {
RED: Symbol('red'),
GREEN: Symbol('green'),
BLUE: Symbol('blue')
};
3. 模拟私有属性
javascript
const _private = Symbol('private');
class MyClass {
constructor(value) {
this[_private] = value;
}
getValue() {
return this[_private];
}
}
const obj = new MyClass('secret');
console.log(obj.getValue()); // 'secret'
console.log(obj._private); // undefined - 无法直接访问
全局 Symbol 注册表
javascript
// 创建/获取全局 Symbol
const globalSym1 = Symbol.for('global.id');
const globalSym2 = Symbol.for('global.id');
console.log(globalSym1 === globalSym2); // true
// 查看 key
console.log(Symbol.keyFor(globalSym1)); // 'global.id'
// 普通 Symbol 没有 key
const localSym = Symbol('local');
console.log(Symbol.keyFor(localSym)); // undefined
内置 Well-Known Symbols
用于自定义对象的行为:
javascript
// Symbol.iterator - 使对象可迭代
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]: function() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
}
return { done: true };
}
};
}
};
for (const item of myIterable) {
console.log(item); // 1, 2, 3
}
// 其他内置 Symbols
// Symbol.hasInstance - 自定义 instanceof
// Symbol.toPrimitive - 类型转换
// Symbol.toStringTag - 修改 toString 标签
// Symbol.species - 控制衍生对象类型
// Symbol.asyncIterator - 异步迭代器
重要注意事项
不会被遍历:
javascript
const sym = Symbol('test');
const obj = {
[sym]: 'secret',
name: 'test'
};
// 以下方法不会包含 Symbol 属性
Object.keys(obj); // ['name']
Object.values(obj); // ['test']
JSON.stringify(obj); // '{"name":"test"}'
Object.getOwnPropertyNames(obj); // ['name']
// 需要专门的方法
Object.getOwnPropertySymbols(obj); // [Symbol(test)]
Reflect.ownKeys(obj); // ['name', Symbol(test)]
类型转换:
javascript
const sym = Symbol('test');
// 可以转为字符串
String(sym); // 'Symbol(test)'
sym.toString(); // 'Symbol(test)'
// 可以转为布尔值
Boolean(sym); // true
// 不能转为数字或字符串拼接
Number(sym); // ❌ TypeError
sym + ''; // ❌ TypeError
`sym: ${sym}`; // ❌ TypeError
实际应用场景
- 防止属性名冲突(特别是库开发)
- 定义枚举常量(确保唯一性)
- 隐藏实现细节(虽然不是真正的私有)
- 自定义对象行为(迭代器、类型转换等)
Symbol 是 JavaScript 中一个非常有用的特性,特别适合需要唯一标识符的场景。