在 JavaScript 中,迭代协议和迭代器协议是两个重要的概念,它们定义了对象如何被迭代以及如何生成一系列值。本文将详细介绍这两个协议,并通过代码示例帮助理解它们的实际应用。
什么是迭代协议?
迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。例如,在 for...of
循环中,哪些值可以被遍历到。以下是迭代协议的两个核心部分:
1. 可迭代协议
要成为可迭代对象,一个对象必须实现 [Symbol.iterator]()
方法。该方法是一个无参函数,返回一个符合迭代器协议的对象。
-
[Symbol.iterator] 的作用
当一个对象需要被迭代时(例如在for...of
中),会调用其[Symbol.iterator]()
方法,返回一个迭代器对象。迭代器对象负责生成迭代的值。 -
实现方式
[Symbol.iterator]()
方法可以是普通函数,也可以是生成器函数。生成器函数可以使用yield
提供每个条目。
2. 迭代器协议
迭代器协议定义了如何生成一系列值。当所有值迭代完毕后,会返回一个默认的结束标志。
- next() 方法
一个对象要成为迭代器,必须实现next()
方法。该方法返回一个对象,包含以下两个属性:done
:布尔值,表示是否迭代完成。value
:当前迭代的值。
内置可迭代对象
以下是一些内置的可迭代对象:
String
Array
TypedArray
Map
Set
Intl.Segments
arguments
对象- 一些 DOM 集合类型(如
NodeList
)
这些对象的原型都实现了 [Symbol.iterator]()
方法。
接受可迭代对象的内置 API
以下内置 API 可以接受可迭代对象:
Map
WeakMap
Set
WeakSet
Promise.all
Promise.allSettled
Promise.any
Promise.race
Array.from
Object.groupBy
Map.groupBy
示例代码
以下是一些代码示例,帮助理解迭代协议和迭代器协议的实际应用。
1. 自定义可迭代对象
const genObj = {
[Symbol.iterator]() {
let i = 0;
return {
next() {
i++;
if (i === 3) {
return { value: undefined, done: true };
}
return { value: i, done: false };
},
return() {
console.log('closing');
return { done: true };
}
};
}
};
const [a, b, c] = genObj; // 解构可迭代对象
console.log(a, b, c); // 1 2 undefined
for (const value of genObj) {
break; // 迭代一次,执行 return 方法
}
2. 使用生成器函数创建迭代器
const myIterator = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
console.log([...myIterator]); // [1, 2, 3]
3. 使用类封装可迭代对象
class SimpleClass {
#data;
constructor(data) {
this.#data = data;
}
*[Symbol.iterator]() {
for (const value of this.#data) {
yield value;
}
}
}
const simple = new SimpleClass([1, 2, 3]);
for (const value of simple) {
console.log(value); // 1, 2, 3
}
4. 重写字符串的迭代器方法
const str = 'hello';
str[Symbol.iterator] = function () {
return {
next() {
if (this._first) {
this._first = false;
return { value: 'bye', done: false };
} else {
return { done: true };
}
},
_first: true
};
};
for (const key of str) {
console.log(key); // bye
}
5. 简单迭代器实现
function createIterator(items) {
let i = 0;
return {
next() {
const done = i >= items.length;
const value = !done ? items[i++] : undefined;
return { done, value };
}
};
}
const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // { done: false, value: 1 }
console.log(iterator.next()); // { done: false, value: 2 }
console.log(iterator.next()); // { done: false, value: 3 }
总结
- 可迭代协议定义了对象如何被迭代,要求实现
[Symbol.iterator]()
方法。 - 迭代器协议定义了如何生成一系列值,要求实现
next()
方法。 - JavaScript 提供了许多内置的可迭代对象和支持迭代的 API。
- 通过生成器函数或自定义类,可以轻松实现自定义的可迭代对象。
理解迭代协议和迭代器协议,不仅有助于掌握 JavaScript 的核心机制,还能帮助我们更高效地处理数据结构和流式数据。