Symbol是JavaScript在ES6阶段新增的一种原始数据类型,和已有的undefined、null、number、string、boolean、bigint共同构成JavaScript的七种原始数据类型,它的核心特点是每个Symbol值都是唯一的,不会和其他任何值相等。

Symbol的基本创建方式
Symbol不能通过new关键字调用,直接调用Symbol函数就可以生成一个唯一的Symbol值,函数可以接收一个可选的描述字符串,用来区分不同的Symbol值,这个描述不会影响Symbol的唯一性。
// 创建无描述的Symbol
const sym1 = Symbol();
// 创建有描述的Symbol
const sym2 = Symbol('id');
const sym3 = Symbol('id');
// 即使描述相同,两个Symbol也不相等
console.log(sym2 === sym3); // 输出 false
Symbol作为对象属性的使用
Symbol最常见的用途是作为对象的属性键,因为Symbol的唯一性,用它作为属性键可以避免属性名冲突,尤其是在给第三方对象或者内置对象添加属性时,不会覆盖原有的属性。
定义Symbol属性
Symbol作为对象属性时,不能使用点运算符定义,必须使用方括号语法,因为点运算符会将后面的内容识别为字符串,而不是Symbol值。
const userSymbol = Symbol('user_id');
const obj = {
[userSymbol]: 1001,
name: '张三'
};
// 访问Symbol属性也需要用方括号
console.log(obj[userSymbol]); // 输出 1001
// 点运算符访问不到Symbol属性
console.log(obj.userSymbol); // 输出 undefined
Symbol属性的遍历特性
对象的常规遍历方法比如for...in、Object.keys()、Object.getOwnPropertyNames()都无法获取到Symbol属性,只有专门的API可以获取对象的Symbol属性。
- Object.getOwnPropertySymbols():返回对象自身的所有Symbol属性数组
- Reflect.ownKeys():返回对象自身的所有键名,包括字符串键和Symbol键
const symA = Symbol('a');
const symB = Symbol('b');
const testObj = {
[symA]: 1,
[symB]: 2,
c: 3
};
console.log(Object.keys(testObj)); // 输出 ["c"]
console.log(Object.getOwnPropertySymbols(testObj)); // 输出 [Symbol(a), Symbol(b)]
console.log(Reflect.ownKeys(testObj)); // 输出 ["c", Symbol(a), Symbol(b)]
Symbol的常用内置值
ES6还提供了一些内置的Symbol值,这些Symbol值被暴露给开发者,用来修改JavaScript的一些内部行为,比如迭代器、类型转换等逻辑。
| 内置Symbol | 作用说明 |
|---|---|
| Symbol.iterator | 指向对象的默认迭代器方法,对象有这个属性就可以被for...of遍历 |
| Symbol.toStringTag | 用于修改Object.prototype.toString.call()返回的结果中的类型标签 |
| Symbol.hasInstance | 用于自定义instanceof运算符的行为 |
内置Symbol使用示例
// 自定义对象的toStringTag
const myObj = {
[Symbol.toStringTag]: 'MyObject'
};
console.log(Object.prototype.toString.call(myObj)); // 输出 "[object MyObject]"
// 自定义类的迭代器
class MyIterable {
constructor(data) {
this.data = data;
}
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
}
return { value: undefined, done: true };
}
};
}
}
const iterable = new MyIterable([1, 2, 3]);
for (const item of iterable) {
console.log(item); // 依次输出 1 2 3
}
Symbol的其他实用场景
定义唯一常量
当需要定义一组不会重复的常量时,使用Symbol可以避免常量值重复的问题,比如定义状态常量,即使描述相同,Symbol值本身也是唯一的。
const STATUS = {
PENDING: Symbol('pending'),
SUCCESS: Symbol('success'),
FAILED: Symbol('failed')
};
function handleStatus(status) {
switch(status) {
case STATUS.PENDING:
console.log('处理中');
break;
case STATUS.SUCCESS:
console.log('处理成功');
break;
case STATUS.FAILED:
console.log('处理失败');
break;
}
}
模拟私有属性
因为Symbol属性默认不会被常规遍历方法获取到,所以可以用来模拟对象的私有属性,外部无法直接访问到这些属性,只能通过内部暴露的方法操作。
const _privateData = Symbol('private_data');
class MyClass {
constructor(data) {
this[_privateData] = data;
}
getData() {
return this[_privateData];
}
}
const instance = new MyClass('私有数据');
console.log(instance.getData()); // 输出 "私有数据"
// 外部无法直接访问私有属性
console.log(instance[_privateData]); // 只有通过获取Symbol才能访问,而Symbol没有暴露出去
Symbol的注意事项
- Symbol值不能和其他类型的值进行运算,否则会报错,比如
Symbol('a') + 1会抛出类型错误 - Symbol可以显式转换为字符串,使用
String()或者toString()方法,也可以转换为布尔值,转换后为true,但是不能转换为数字 - 如果需要复用同一个Symbol值,可以使用
Symbol.for()方法,这个方法会先在全局Symbol注册表中查找是否有对应描述的Symbol,有就返回,没有就新建并注册
const symFor1 = Symbol.for('test');
const symFor2 = Symbol.for('test');
console.log(symFor1 === symFor2); // 输出 true,因为是同一个Symbol
// Symbol.keyFor()可以获取全局注册的Symbol的描述
console.log(Symbol.keyFor(symFor1)); // 输出 "test"
// 未全局注册的Symbol用Symbol.keyFor()返回undefined
const symNormal = Symbol('test');
console.log(Symbol.keyFor(symNormal)); // 输出 undefined
JavaScriptSymbol数据类型ES6修改时间:2026-07-19 12:00:29