Iterator
(迭代器)是 ES6 引入的一种 接口,用于 顺序访问 可迭代对象(Array
、Set
、Map
、String
、arguments
、自定义对象等)。
Iterator(迭代器)的作用有三个:
- 为各种数据结构提供一个统一的、简便的访问接口
- 使数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
1. 迭代器的基本概念
(1) 迭代器是什么?
- 迭代器是一种 特殊对象,提供
next()
方法,每次调用都会返回:{ value: 当前值, done: 是否完成 }
- 当
done: true
时,表示迭代结束。
Iterator 的遍历过程
// Iterator 的遍历过程如下:
1. 创建一个指针对象,指向当前数据结构的起始位置
2. 第一次调用指针对象的 next 方法,可以将指针指向数据结构的第一个成员
3. 第二次调用指针对象的 next 方法,指针就指向数据结构的第二个成员
4. 不断调用指针对象的 next 方法,直到它指向数据结构的结束位置
// 每一次调用 next 方法,都会返回一个包含 value 和 done 两个属性的对象
{
value: 当前成员的值,
done: 布尔值,表示遍历是否结束
}
2. 生成迭代器
(1) 手动创建迭代器
function createIterator(arr) {
let index = 0;
return {
next: function () {
return index < arr.length
? { value: arr[index++], done: false }
: { value: undefined, done: true };
}
};
}
let iterator = createIterator(["a", "b", "c"]);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
📌 每次 next()
调用,都会返回 value
并前进。
(2) 使用 Symbol.iterator
所有 可迭代对象(Array
、Set
、Map
等)都有 默认的迭代器,可以用 Symbol.iterator
访问:
let arr = ["x", "y", "z"];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 'x', done: false }
console.log(iterator.next()); // { value: 'y', done: false }
console.log(iterator.next()); // { value: 'z', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
📌 数组、字符串、Set、Map 都有 Symbol.iterator
,可直接迭代。
(3) 自定义对象的迭代器
普通对象没有默认迭代器,需手动实现:
let myObj = {
data: [10, 20, 30],
[Symbol.iterator]: function () {
let index = 0;
return {
next: () => {
return index < this.data.length
? { value: this.data[index++], done: false }
: { value: undefined, done: true };
}
};
}
};
let iter = myObj[Symbol.iterator]();
console.log(iter.next()); // { value: 10, done: false }
console.log(iter.next()); // { value: 20, done: false }
console.log(iter.next()); // { value: 30, done: false }
console.log(iter.next()); // { value: undefined, done: true }
📌 对象没有默认迭代器,需实现 Symbol.iterator
才能用 for...of
。
3. for...of
遍历迭代器
所有 实现 Symbol.iterator
的对象,都可以用 for...of
遍历:
let arr = ["A", "B", "C"];
for (let char of arr) {
console.log(char);
}
// A
// B
// C
📌 相比 forEach()
,for...of
可与 break
、continue
配合使用。
4. 可迭代对象
✅ 可以使用 for...of
、Symbol.iterator
的对象
Array
String
Set
Map
arguments
NodeList
- 自定义对象(需实现
Symbol.iterator
)
5. Set
和 Map
的迭代器
(1) Set
迭代
let mySet = new Set(["apple", "banana", "cherry"]);
let setIter = mySet[Symbol.iterator]();
console.log(setIter.next()); // { value: 'apple', done: false }
console.log(setIter.next()); // { value: 'banana', done: false }
console.log(setIter.next()); // { value: 'cherry', done: false }
console.log(setIter.next()); // { value: undefined, done: true }
📌 Set
按插入顺序存储,迭代返回唯一值。
(2) Map
迭代
let myMap = new Map([
["name", "Alice"],
["age", 25]
]);
for (let [key, value] of myMap) {
console.log(key, value);
}
// name Alice
// age 25
📌 Map
迭代时返回 [key, value]
数组。
6. 迭代器 vs 生成器
特性 | 迭代器 (Iterator) | 生成器 (Generator) |
---|---|---|
创建方式 | 手动实现 next() | function* 生成 |
使用 Symbol.iterator | 需要手动实现 | 生成器自动实现 |
可暂停执行 | ❌ 否 | ✅ 是(可 yield ) |
示例:生成器
function* generatorFunction() {
yield "A";
yield "B";
yield "C";
}
let gen = generatorFunction();
console.log(gen.next()); // { value: 'A', done: false }
console.log(gen.next()); // { value: 'B', done: false }
console.log(gen.next()); // { value: 'C', done: false }
console.log(gen.next()); // { value: undefined, done: true }
📌 生成器更简洁,支持 yield
暂停执行。
7. Iterator 使用场景
7.1 解构赋值
// 对数组和 Set 结构进行解构赋值时,会默认调用 Iterator 接口
let set = new Set().add('a').add('b').add('c');
let [x, y] = set; // x='a'; y='b'
7.2 扩展运算符
// 扩展运算符(...)也会调用默认的 Iterator 接口
let str = 'hello';
[...str] // ['h', 'e', 'l', 'l', 'o']
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
7.3 yield*
// yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口
let generator = function* () {
yield 1;
yield* [2, 3, 4];
yield 5;
};
for (let v of generator()) {
console.log(v);
}
// 1, 2, 3, 4, 5
8. 注意事项
8.1 对象的 for…of 循环
// 对象默认不具备 Iterator 接口,不能直接使用 for...of
let obj = { a: 1, b: 2, c: 3 };
for (let value of obj) {
console.log(value); // TypeError: obj is not iterable
}
// 正确的遍历对象方式
// 1. 使用 Object.keys()
for (let key of Object.keys(obj)) {
console.log(key + ': ' + obj[key]);
}
// 2. 使用 Object.entries()
for (let [key, value] of Object.entries(obj)) {
console.log(key + ': ' + value);
}
8.2 Iterator 接口与 Generator 函数
// 使用 Generator 函数实现 Iterator 接口
let obj = {
*[Symbol.iterator]() {
yield 'hello';
yield 'world';
}
};
for (let x of obj) {
console.log(x);
}
// hello
// world
9. 最佳实践
9.1 为类部署 Iterator 接口
class Collection {
constructor() {
this.items = [];
}
add(item) {
this.items.push(item);
}
*[Symbol.iterator]() {
for (let item of this.items) {
yield item;
}
}
}
let collection = new Collection();
collection.add('foo');
collection.add('bar');
for (let value of collection) {
console.log(value);
}
// foo
// bar
9.2 异步迭代器
// ES2018 引入了异步迭代器
const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield 'hello';
yield 'async';
yield 'iteration';
}
};
(async () => {
for await (const x of asyncIterable) {
console.log(x);
}
})();
// hello
// async
// iteration
10. 适用场景
✅ 适用于
- 遍历数组、字符串、Set、Map
- 自定义可迭代对象
- 流式处理数据(类似分页加载)
- 避免一次性加载大数据(生成器)
11. 总结
Iterator
是 ES6 提供的一种接口,用于顺序访问集合。Symbol.iterator
让对象变成可迭代,可用于for...of
、spread
。Set
、Map
、Array
、String
默认实现Symbol.iterator
,可直接迭代。- 生成器 (
Generator
) 自动创建迭代器,可暂停执行 (yield
),更强大。