1. Symbol 基本概念
1.1 创建 Symbol
const s1 = Symbol();
const s2 = Symbol('description');
console.log(Symbol() === Symbol());
console.log(Symbol('key') === Symbol('key'));
1.2 Symbol.for() 和 Symbol.keyFor()
const s1 = Symbol.for('shared');
const s2 = Symbol.for('shared');
console.log(s1 === s2);
console.log(Symbol.keyFor(s1));
console.log(Symbol.keyFor(Symbol('not shared')));
2. Symbol 作为对象属性
2.1 基本用法
const mySymbol = Symbol('mySymbol');
const obj = {
[mySymbol]: 'Hello Symbol'
};
console.log(obj[mySymbol]);
obj[Symbol('anotherSymbol')] = 'Another value';
2.2 Symbol 属性的特点
const obj = {
[Symbol('name')]: 'John',
age: 25
};
console.log(Object.keys(obj));
console.log(Object.getOwnPropertyNames(obj));
console.log(Object.getOwnPropertySymbols(obj));
console.log(Reflect.ownKeys(obj));
3. 内置 Symbol 值
3.1 Symbol.iterator 迭代器
const collection = {
items: ['item1', 'item2', 'item3'],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
return {
done: index >= this.items.length,
value: this.items[index++]
};
}
};
}
};
for (const item of collection) {
console.log(item);
}
3.2 Symbol.toStringTag
class CustomClass {
get [Symbol.toStringTag]() {
return 'CustomClass';
}
}
const obj = new CustomClass();
console.log(Object.prototype.toString.call(obj));
3.3 Symbol.species
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const arr = new MyArray(1, 2, 3);
const mapped = arr.map(x => x * 2);
4. 实际应用场景
4.1 私有属性模拟
const privateProperty = Symbol('privateProperty');
const privateMethod = Symbol('privateMethod');
class MyClass {
constructor() {
this[privateProperty] = 'private value';
}
[privateMethod]() {
return 'private method';
}
publicMethod() {
return this[privateMethod]();
}
}
const instance = new MyClass();
console.log(instance[privateProperty]);
4.2 防止属性名冲突
const librarySymbol = Symbol('myLibrary');
class ThirdPartyClass {
constructor() {
this[librarySymbol] = {
config: {},
cache: new Map()
};
}
}
4.3 实现特定的接口或协议
const protocol = {
connect: Symbol('connect'),
disconnect: Symbol('disconnect')
};
class Device {
[protocol.connect]() {
console.log('Device connected');
}
[protocol.disconnect]() {
console.log('Device disconnected');
}
}
5. Symbol 与元编程
5.1 自定义对象的基本行为
const myObject = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number':
return 42;
case 'string':
return 'custom string';
default:
return 'default';
}
}
};
console.log(+myObject);
console.log(\`\${myObject}\`); // 'custom string'
5.2 自定义对象的检查行为
const customInspect = Symbol.for('nodejs.util.inspect.custom');
class CustomObject {
[customInspect]() {
return 'CustomObject(...)';
}
}
console.log(new CustomObject());
6. 最佳实践
6.1 使用建议
const userToken = Symbol('user authentication token');
const STATUS = {
PENDING: Symbol('pending'),
FULFILLED: Symbol('fulfilled'),
REJECTED: Symbol('rejected')
};
const _data = Symbol('private data');
class MyClass {
constructor() {
this[_data] = {};
}
}
6.2 注意事项
const sym = new Symbol();
const sym = Symbol('my symbol');
alert(sym);
alert(sym.toString());
alert(sym.description);
const obj = {
[Symbol('id')]: 1,
name: 'John'
};
console.log(JSON.stringify(obj));
7. Symbol 的遍历方法
7.1 不同遍历方法的对比
const obj = {
name: 'John',
age: 25,
[Symbol('id')]: 1,
[Symbol('key')]: 'value'
};
console.log(Object.keys(obj));
console.log(Object.getOwnPropertyNames(obj));
console.log(Object.getOwnPropertySymbols(obj));
console.log(Reflect.ownKeys(obj));
7.2 实际应用示例
7.2.1 获取对象的所有 Symbol 属性
function getAllSymbolProperties(obj) {
return Object.getOwnPropertySymbols(obj)
.reduce((result, symbol) => {
result[symbol.description] = obj[symbol];
return result;
}, {});
}
const user = {
name: 'John',
[Symbol('id')]: 123,
[Symbol('role')]: 'admin'
};
console.log(getAllSymbolProperties(user));
7.2.2 合并包含 Symbol 的对象
function mergeWithSymbols(target, ...sources) {
sources.forEach(source => {
Object.assign(target, source);
Object.getOwnPropertySymbols(source).forEach(symbol => {
target[symbol] = source[symbol];
});
});
return target;
}
const baseConfig = {
name: 'config',
[Symbol('secret')]: 'xyz'
};
const extraConfig = {
version: '1.0',
[Symbol('key')]: '123'
};
const finalConfig = mergeWithSymbols({}, baseConfig, extraConfig);
console.log(Reflect.ownKeys(finalConfig));
7.2.3 深度克隆包含 Symbol 的对象
function deepCloneWithSymbols(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const clone = Array.isArray(obj) ? [] : {};
Reflect.ownKeys(obj).forEach(key => {
clone[key] = deepCloneWithSymbols(obj[key]);
});
return clone;
}
const original = {
name: 'test',
[Symbol('id')]: 1,
nested: {
[Symbol('key')]: 'value'
}
};
const cloned = deepCloneWithSymbols(original);
console.log(
Object.getOwnPropertySymbols(cloned).length ===
Object.getOwnPropertySymbols(original).length
);
7.3 遍历方法的使用建议
function processAllProperties(obj) {
Reflect.ownKeys(obj).forEach(key => {
console.log(key, obj[key]);
});
}
function processSymbolsOnly(obj) {
Object.getOwnPropertySymbols(obj).forEach(symbol => {
console.log(symbol.description, obj[symbol]);
});
}
function processPropertiesSeparately(obj) {
Object.keys(obj).forEach(key => {
console.log('Regular:', key, obj[key]);
});
Object.getOwnPropertySymbols(obj).forEach(symbol => {
console.log('Symbol:', symbol.description, obj[symbol]);
});
}
7.4 性能考虑
function optimizedPropertyProcessing(obj) {
const symbols = Object.getOwnPropertySymbols(obj);
if (symbols.length > 0) {
const symbolProps = {};
symbols.forEach(symbol => {
symbolProps[symbol.description] = obj[symbol];
});
}
const regularKeys = Object.keys(obj);
const batchSize = 1000;
for (let i = 0; i < regularKeys.length; i += batchSize) {
const batch = regularKeys.slice(i, i + batchSize);
batch.forEach(key => {
});
}
}