TypeScript 迭代器与生成器
迭代器和生成器是 JavaScript/TypeScript 中处理集合的重要模式。
它们提供了一种统一的遍历数据的方式,让处理大数据流、无限序列等变得更加简单。
为什么需要迭代器和生成器
在处理集合数据时,我们经常需要遍历数组、对象等数据结构。
迭代器提供了一种统一的、可自定义的遍历接口,让任何对象都可以被遍历。
生成器是创建迭代器的简洁方式,它允许你使用函数来暂停和恢复执行,非常适合处理大数据流或无限序列。
概念说明:迭代器是一个对象,它提供 next() 方法用于遍历数据。生成器是一种特殊的函数,可以在执行过程中暂停并返回一个值。
可迭代协议
实现 Symbol.iterator 方法的对象可以被 for...of 循环遍历。
实例
var arr = [1, 2, 3];
for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
var item = arr_1[_i];
console.log("数组元素: " + item);
}
// 字符串默认可迭代
var str = "hello";
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
var char = str_1[_i];
console.log("字符: " + char);
}
运行结果:
数组元素: 1 数组元素: 2 数组元素: 3 字符: h 字符: e 字符: l 字符: l 字符: o
说明:数组和字符串都内置实现了 Symbol.iterator 方法,所以可以直接使用 for...of 遍历。
自定义可迭代对象
让普通对象实现 Symbol.iterator 接口,使其可被遍历。
实例
var range = {
from: 1,
to: 5,
// 实现 Symbol.iterator 方法
[Symbol.iterator]: function() {
return {
current: this.from,
last: this.to,
// next 方法返回迭代结果
next: function() {
if (this.current <= this.last) {
// 未完成,返回当前值并递增
return { done: false, value: this.current++ };
}
// 已完成
return { done: true, value: undefined };
}
};
}
};
// 使用 for...of 遍历
for (var _i = 0, range_1 = range; _i < range_1.length; _i++) {
var num = range_1[_i];
console.log("范围: " + num);
}
迭代器协议:迭代器必须有一个 next() 方法,返回 { done: boolean, value: any } 格式的对象。
生成器函数
使用 function* 语法创建生成器,使用 yield 暂停执行并返回值。
实例
function* numberGenerator() {
yield 1; // 暂停并返回 1
yield 2; // 暂停并返回 2
yield 3; // 暂停并返回 3
}
// 创建生成器实例
var gen = numberGenerator();
// 每次调用 next() 都会执行到下一个 yield
console.log("第一个: " + gen.next().value);
console.log("第二个: " + gen.next().value);
console.log("第三个: " + gen.next().value);
console.log("完成: " + gen.next().done);
运行结果:
第一个: 1 第二个: 2 第三个: 3 完成: true
生成器:生成器函数会返回一个迭代器,每次调用 next() 都会执行到下一个 yield 语句。
无限生成器
生成器可以产生无限序列,由于是惰性求值,不会占用无限内存。
实例
// 每次调用只生成一个数字,不会一次性生成所有数字
function* infiniteNumbers() {
var n = 1;
while (true) { // 无限循环
yield n++; // 暂停并返回当前值,然后递增
}
}
var gen = infiniteNumbers();
console.log("第1个: " + gen.next().value);
console.log("第2个: " + gen.next().value);
console.log("第3个: " + gen.next().value);
// 只获取前5个数字
var nums = [];
var iter = infiniteNumbers();
for (var i = 0; i < 5; i++) {
nums.push(iter.next().value);
}
console.log("前5个: " + nums);
运行结果:
第1个: 1 第2个: 2 第3个: 3 前5个: 1,2,3,4,5
惰性求值:生成器的最大优势是惰性求值,只有在调用 next() 时才会计算下一个值,非常适合处理无限序列。
委托生成器
使用 yield* 委托另一个生成器或可迭代对象。
实例
function* gen1() {
yield 1;
yield 2;
}
// 第二个生成器
function* gen2() {
yield 3;
yield 4;
}
// 组合生成器:使用 yield* 委托
function* combined() {
yield* gen1(); // 委托给 gen1
yield* gen2(); // 委托给 gen2
}
// 遍历组合生成器
for (var _i = 0, combined_1 = combined(); _i < combined_1.length; _i++) {
var num = combined_1[_i];
console.log("值: " + num);
}
运行结果:
值: 1 值: 2 值: 3 值: 4
yield*:委托生成器可以组合多个生成器或可迭代对象,非常适合构建可复用的数据流。
TypeScript 生成器类型
生成器的类型注解使用 Generator 类型。
实例
function* idGenerator(): Generator<number, void, unknown> {
var i = 1;
while (i <= 3) {
yield i++; // yield number 类型
}
// return void
}
var gen = idGenerator();
console.log(Array.from(gen));
类型说明:Generator<T, R, N> 表示:T 是 yield 的类型,R 是最终返回的类型,N 是 next() 参数的类型。
注意事项
- 迭代器协议:实现 Symbol.iterator 返回带 next() 方法的对象
- 生成器语法:使用 function* 而非 function
- yield 关键字:暂停执行并返回值
- 惰性计算:生成器按需计算,不会一次性生成所有值
最佳实践:处理大数据流、无限序列或需要暂停/恢复的场景时,使用生成器。
总结
迭代器和生成器是 TypeScript 中强大的数据处理工具。
- 可迭代对象:实现 Symbol.iterator 接口
- 生成器:使用 function* 和 yield 创建
- yield:暂停执行并返回值
- 委托:使用 yield* 组合多个生成器
建议:在需要遍历自定义对象、处理数据流或创建无限序列时,使用迭代器和生成器。
点我分享笔记