Symbol 是 ES6 引入的原始数据类型,用于创建唯一的标识符。
// 创建 Symbol
const sym1 = Symbol();
const sym2 = Symbol('description');
const sym3 = Symbol('description');
console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)
console.log(sym2 === sym3); // false (每个 Symbol 都是唯一的)
const sym1 = Symbol('id');
const sym2 = Symbol('id');
console.log(sym1 === sym2); // false
const sym = Symbol('test');
console.log(typeof sym); // 'symbol'
const obj = {
name: 'Alice',
[Symbol('id')]: 123
};
console.log(Object.keys(obj)); // ['name']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(id)]
const sym1 = Symbol.for('key');
const sym2 = Symbol.for('key');
console.log(sym1 === sym2); // true (同一个 Symbol)
const sym3 = Symbol('key');
console.log(sym1 === sym3); // false
const sym = Symbol.for('myKey');
console.log(Symbol.keyFor(sym)); // 'myKey'
const localSym = Symbol('local');
console.log(Symbol.keyFor(localSym)); // undefined
const obj = {
values: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.values.length) {
return { value: this.values[index++], done: false };
}
return { done: true };
}
};
}
};
for (const value of obj) {
console.log(value); // 1, 2, 3
}
class MyClass {
get [Symbol.toStringTag]() {
return 'MyClass';
}
}
const obj = new MyClass();
console.log(obj.toString()); // '[object MyClass]'
const obj = {
value: 10,
[Symbol.toPrimitive](hint) {
if (hint === 'number') {
return this.value;
}
if (hint === 'string') {
return String(this.value);
}
return this.value;
}
};
console.log(+obj); // 10 (number)
console.log(String(obj)); // '10' (string)
console.log(obj + 5); // 15 (default)
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
const arr1 = [1, 2];
const arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr1.concat(arr2)); // [1, 2, [3, 4]]
const _name = Symbol('name');
const _age = Symbol('age');
class Person {
constructor(name, age) {
this[_name] = name;
this[_age] = age;
}
getName() {
return this[_name];
}
}
const person = new Person('Alice', 25);
console.log(person.getName()); // 'Alice'
console.log(person[_name]); // 'Alice' (仍可访问,但需要 Symbol)
console.log(Object.keys(person)); // [] (不可枚举)
const METADATA = Symbol('metadata');
function addMetadata(obj, data) {
obj[METADATA] = data;
}
function getMetadata(obj) {
return obj[METADATA];
}
const obj = { name: 'Alice' };
addMetadata(obj, { created: Date.now(), version: '1.0' });
console.log(getMetadata(obj)); // { created: ..., version: '1.0' }
console.log(Object.keys(obj)); // ['name'] (不影响普通属性)
// 库 A
const ID = Symbol('id');
function setID(obj, id) {
obj[ID] = id;
}
// 库 B
const ID = Symbol('id'); // 不同的 Symbol,不会冲突
function setID(obj, id) {
obj[ID] = id;
}
const obj = {};
setID(obj, 1); // 库 A
setID(obj, 2); // 库 B
// 两个 ID 互不干扰
const STATUS = {
PENDING: Symbol('pending'),
FULFILLED: Symbol('fulfilled'),
REJECTED: Symbol('rejected')
};
function handleStatus(status) {
switch (status) {
case STATUS.PENDING:
return '处理中';
case STATUS.FULFILLED:
return '已完成';
case STATUS.REJECTED:
return '已拒绝';
}
}
const INSTANCE = Symbol('instance');
class Singleton {
constructor() {
if (Singleton[INSTANCE]) {
return Singleton[INSTANCE];
}
Singleton[INSTANCE] = this;
return this;
}
}
const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1 === s2); // true
class Collection {
constructor(items) {
this.items = items;
}
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.items.length) {
return { value: this.items[index++], done: false };
}
return { done: true };
}
};
}
}
const collection = new Collection([1, 2, 3]);
for (const item of collection) {
console.log(item); // 1, 2, 3
}
const sym = Symbol('key');
const obj = {
[sym]: 'value',
name: 'Alice'
};
// 访问 Symbol 属性
console.log(obj[sym]); // 'value'
// 获取所有 Symbol 属性
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(key)]
// 获取所有属性(包括 Symbol)
console.log(Reflect.ownKeys(obj)); // ['name', Symbol(key)]
// Symbol 属性不可枚举
console.log(Object.keys(obj)); // ['name']
for (const key in obj) {
console.log(key); // 'name' (不包括 Symbol)
}
const sym = new Symbol(); // TypeError: Symbol is not a constructor
const sym = Symbol('test');
String(sym); // 'Symbol(test)'
sym.toString(); // 'Symbol(test)'
// sym + ''; // TypeError: Cannot convert a Symbol value to a string
const sym = Symbol();
console.log(Boolean(sym)); // true
if (sym) {
console.log('truthy');
}
const obj = {
name: 'Alice',
[Symbol('id')]: 123
};
console.log(JSON.stringify(obj)); // '{"name":"Alice"}'
const sym = Symbol('key');
class Parent {
[sym] = 'parent';
}
class Child extends Parent {}
const child = new Child();
console.log(child[sym]); // 'parent' (可以访问,因为是实例属性)
| Symbol | 用途 | |--------|------| | Symbol.iterator | 定义默认迭代器 | | Symbol.toStringTag | 自定义 toString 标签 | | Symbol.toPrimitive | 自定义类型转换 | | Symbol.hasInstance | 自定义 instanceof | | Symbol.species | 指定衍生对象构造函数 | | Symbol.isConcatSpreadable | 控制 concat 展开 | | Symbol.match | 自定义 match 行为 | | Symbol.replace | 自定义 replace 行为 | | Symbol.search | 自定义 search 行为 | | Symbol.split | 自定义 split 行为 |
const USER_ID = Symbol('user.id');
const SESSION_TOKEN = Symbol('session.token');
// module.js
export const PRIVATE_KEY = Symbol('private');
// 使用时
import { PRIVATE_KEY } from './module.js';
obj[PRIVATE_KEY] = 'value';
// 跨模块共享
const SHARED_KEY = Symbol.for('shared.key');