Symbol 的基本概念
Symbol 是 ES6 引入的一种新的原始数据类型,表示独一无二的值。Symbol 值通过 Symbol()
函数生成,即使传入相同的描述符,生成的 Symbol 值也不相等。
javascript
const s1 = Symbol('foo');
const s2 = Symbol('foo');
console.log(s1 === s2); // false
Symbol 的描述符主要用于调试,可以通过 description
属性获取。
javascript
console.log(s1.description); // 'foo'
Symbol 的使用场景
Symbol 主要用于对象属性的键,避免属性名冲突。由于 Symbol 值唯一,适合作为对象的私有属性或特殊标识。
javascript
const obj = {
[Symbol('key')]: 'value'
};
console.log(obj[Symbol('key')]); // undefined,因为 Symbol 值不同
Symbol 还可以用于定义类的私有成员。
javascript
const _private = Symbol('private');
class MyClass {
constructor() {
this[_private] = 'secret';
}
getSecret() {
return this[_private];
}
}
内置 Symbol 值
ES6 提供了许多内置的 Symbol 值,用于实现语言内部行为。例如:
Symbol.iterator
: 定义对象的默认迭代器。Symbol.toStringTag
: 定制对象的toString()
行为。Symbol.hasInstance
: 定制instanceof
操作符的行为。
javascript
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
迭代器与可迭代协议
迭代器是一种设计模式,允许按照顺序访问集合对象的元素。ES6 引入了可迭代协议和迭代器协议。
- 可迭代协议 : 对象必须实现
@@iterator
方法(即Symbol.iterator
属性),返回一个迭代器。 - 迭代器协议 : 迭代器必须实现
next()
方法,返回{ value, done }
对象。
javascript
const iterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (const value of iterable) {
console.log(value); // 1, 2, 3
}
生成器与迭代器
生成器函数(function*
)返回一个生成器对象,该对象既是迭代器,也是可迭代对象。生成器简化了迭代器的实现。
javascript
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = simpleGenerator();
console.log(gen.next().value); // 1
console.log([...gen]); // [2, 3]
内置可迭代对象
许多 ES6 内置对象是可迭代的,例如数组、Set、Map、字符串等。它们都实现了 Symbol.iterator
方法。
javascript
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next().value); // 1
自定义可迭代对象
通过实现 Symbol.iterator
方法,可以自定义对象的迭代行为。
javascript
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const range = new Range(1, 5);
console.log([...range]); // [1, 2, 3, 4, 5]
Symbol 与迭代器的结合
Symbol 和迭代器可以结合使用,实现更灵活的对象行为。例如,通过 Symbol.iterator
定义对象的默认迭代方式。
javascript
const obj = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
}
return { value: undefined, done: true };
}
};
}
};
console.log([...obj]); // [1, 2, 3]
总结
Symbol 是 ES6 引入的独一无二的值,可用于对象属性的键或特殊标识。迭代器协议和可迭代协议提供了统一的遍历机制。生成器简化了迭代器的实现。通过 Symbol.iterator
可以自定义对象的迭代行为。这些特性为 JavaScript 提供了更强大的元编程能力。