当前位置: 首页 > article >正文

深入理解 TypeScript 中的迭代器(Iterators)与生成器(Generators)

一、为什么需要迭代协议?

在现代 JavaScript/TypeScript 开发中,我们经常需要处理各种集合型数据:数组、Map、Set 甚至是自定义数据结构。ES6 引入的迭代协议(Iteration Protocols)正是为了解决统一遍历机制的问题。通过迭代器模式,我们可以:

  1. 为不同的数据结构提供统一的访问接口

  2. 实现惰性计算(Lazy Evaluation)

  3. 支持现代语言特性(for...of, 扩展运算符等)

  4. 构建异步迭代流程

二、迭代器(Iterator)的核心机制

2.1 迭代协议双接口

TypeScript 通过两个核心接口实现迭代协议:

// 可迭代接口
interface Iterable<T> {[Symbol.iterator](): Iterator<T>;
}// 迭代器接口
interface Iterator<T> {next(): IteratorResult<T>;
}interface IteratorResult<T> {value: T | undefined;done: boolean;
}

2.2 自定义迭代器实战

让我们实现一个简单的数字范围迭代器:

class RangeIterator implements Iterator<number> {private current: number;constructor(private readonly start: number,private readonly end: number,private readonly step: number = 1) {this.current = start;}next(): IteratorResult<number> {if (this.current <= this.end) {const value = this.current;this.current += this.step;return { value, done: false };}return { value: undefined, done: true };}
}// 使用示例
const range = new RangeIterator(1, 5);
let result = range.next();
while (!result.done) {console.log(result.value); // 1, 2, 3, 4, 5result = range.next();
}

2.3 内置可迭代对象

TypeScript 支持以下内置可迭代类型:

类型迭代行为
Array按索引顺序迭代元素
String按字符迭代
Map迭代 [key, value] 键值对
Set按插入顺序迭代元素
NodeListDOM 节点集合迭代
arguments函数参数对象的迭代

三、生成器(Generator)的魔法

3.1 生成器基础语法

通过 function* 声明生成器函数:

function* simpleGenerator() {yield 1;yield 2;yield 3;
}const gen = simpleGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

3.2 生成器高级特性

双向通信
function* twoWayCommunication() {const name = yield 'Please enter your name:';const age = yield 'Please enter your age:';return { name, age };
}const gen = twoWayCommunication();
console.log(gen.next());    // { value: 'Please enter your name:', done: false }
console.log(gen.next('Alice')); // { value: 'Please enter your age:', done: false }
console.log(gen.next(30));  // { value: { name: 'Alice', age: 30 }, done: true }
异常处理
function* errorHandling() {try {yield 'Normal execution';throw new Error('Generator error');} catch (err) {yield `Caught error: ${err.message}`;}
}const gen = errorHandling();
console.log(gen.next()); // { value: 'Normal execution', done: false }
console.log(gen.throw(new Error('External error'))); // { value: 'Caught error: External error', done: false }

3.3 生成器实现迭代器

生成器可以极大简化迭代器的实现:

function* rangeGenerator(start: number, end: number, step = 1) {for (let i = start; i <= end; i += step) {yield i;}
}// 使用 for...of 迭代
for (const num of rangeGenerator(1, 5)) {console.log(num); // 1, 2, 3, 4, 5
}

四、异步迭代与生成器

4.1 异步迭代协议

interface AsyncIterable<T> {[Symbol.asyncIterator](): AsyncIterator<T>;
}interface AsyncIterator<T> {next(): Promise<IteratorResult<T>>;
}

4.2 异步生成器实战

实现分页数据获取:

async function* paginatedFetcher(url: string, pageSize = 10) {let page = 1;let hasMore = true;while (hasMore) {const response = await fetch(`${url}?page=${page}&size=${pageSize}`);const data = await response.json();yield data.items;hasMore = data.hasMore;page++;}
}// 使用示例
(async () => {const pageIterator = paginatedFetcher('/api/data');for await (const items of pageIterator) {console.log('Received items:', items);}
})();

五、性能优化与最佳实践

  1. 惰性计算优势:生成器只在需要时产生值,显著降低内存消耗

    function* fibonacci() {let [a, b] = [0, 1];while (true) {yield a;[a, b] = [b, a + b];}
    }// 仅计算需要的斐波那契数
    const fib = fibonacci();
    console.log(fib.next().value); // 0
    console.log(fib.next().value); // 1

  2. 组合迭代器模式

    function* filter<T>(iterable: Iterable<T>, predicate: (item: T) => boolean) {for (const item of iterable) {if (predicate(item)) {yield item;}}
    }function* map<T, U>(iterable: Iterable<T>, mapper: (item: T) => U) {for (const item of iterable) {yield mapper(item);}
    }// 使用组合
    const numbers = [1, 2, 3, 4, 5];
    const result = map(filter(numbers, n => n % 2 === 0), n => n * 2);
    console.log([...result]); // [4, 8]

  3. 内存优化对比

    方法内存占用执行方式
    传统数组处理立即执行
    生成器管道按需执行
    异步生成器极低事件驱动

六、在常见库中的应用

  1. RxJS:Observable 与生成器的结合

    import { from, Observable } from 'rxjs';function* sensorData() {while (true) {yield Math.random() * 100;await sleep(1000);}
    }const observable$ = from(sensorData());
    observable$.subscribe(console.log);

  2. Redux-Saga:使用生成器管理副作用

    import { call, put, takeEvery } from 'redux-saga/effects';function* fetchUser(action) {try {const user = yield call(fetch, `/api/users/${action.payload}`);yield put({ type: 'USER_FETCH_SUCCEEDED', payload: user });} catch (e) {yield put({ type: 'USER_FETCH_FAILED', message: e.message });}
    }function* mySaga() {yield takeEvery('USER_FETCH_REQUESTED', fetchUser);
    }

七、调试技巧与常见陷阱

7.1 调试建议

  1. 使用 debugger 语句暂停生成器执行

    function* debugGenerator() {yield 'step 1';debugger; // 调试器将在此暂停yield 'step 2';
    }

  2. 利用 VS Code 的调试配置:

    {"type": "node","request": "launch","name": "Debug Generator","skipFiles": ["<node_internals>/**"],"program": "${file}","runtimeArgs": ["--harmony-async-iteration"]
    }

7.2 常见错误处理

  1. 提前终止迭代

    function* numbers() {try {yield 1;yield 2;yield 3;} finally {console.log('Generator cleanup');}
    }const gen = numbers();
    console.log(gen.next()); // { value: 1, done: false }
    console.log(gen.return()); // 立即触发 finally 块

  2. 处理迭代器耗尽

    const gen = simpleGenerator();
    gen.next(); // { value: 1, done: false }
    gen.next(); // { value: 2, done: false }
    gen.next(); // { value: 3, done: false }
    gen.next(); // { value: undefined, done: true }// 安全检测
    function safeNext<T>(iterator: Iterator<T>) {const result = iterator.next();return result.done ? null : result.value;
    }

结语:迭代模式的未来

随着 JavaScript 语言的演进,迭代器和生成器正在成为现代 Web 开发的核心模式。从 React 的 Suspense 特性到 Node.js 的 Stream 处理,从大数据处理到机器学习管道,迭代协议提供了统一的抽象层。掌握这些特性不仅能够提升代码质量,更能帮助我们构建更高效、更易维护的应用程序。

相关文章:

深入理解 TypeScript 中的迭代器(Iterators)与生成器(Generators)

一、为什么需要迭代协议&#xff1f; 在现代 JavaScript/TypeScript 开发中&#xff0c;我们经常需要处理各种集合型数据&#xff1a;数组、Map、Set 甚至是自定义数据结构。ES6 引入的迭代协议&#xff08;Iteration Protocols&#xff09;正是为了解决统一遍历机制的问题。通…...

靶场(十四)---小白心得思路分享---Extplorer

启程&#xff1a; 开始扫描端口服务&#xff0c;发现什么都没有&#xff0c;果断进行下一步目录扫描 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 98:4e:5d:e1:e6:97:29:6f:…...

逆向中常见的加密算法识别

1、base64及换表 base64主要是将输入的每3字节&#xff08;共24bit&#xff09;按照每六比特分成一组&#xff0c;变成4个小于64的索引值&#xff0c;然后通过一个索引表得到4个可见的字符。 索引表为一个64字节的字符串&#xff0c;如果在代码中发现引用了这个索引表“ABCDEF…...

【初学者】怎样学习、使用与研究算法?

李升伟 整理 学习、使用与研究算法是一个系统化的过程&#xff0c;涉及理论学习、实践应用和深入研究。以下从学习方法、使用技巧和研究方向三个方面进行详细阐述&#xff1a; 一、学习方法 1. 分阶段学习 初级阶段&#xff1a;掌握经典算法&#xff0c;如最短路径算法&…...

【愚公系列】《高效使用DeepSeek》018-错题本整理

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...

Linux上的`i2c-tools`工具集的编译构建和安装

源码复制到Ubuntu系统中并解压 的i2c-tools工具集的源码百度网盘下载链接&#xff1a; https://pan.baidu.com/s/1XNuMuT1auT1dMzYo3LAFmw?pwdi6xe 终端进入源码目录 cd /home/book/mybuild/i2c-tools-4.2执行编译构建命令 运行下面的命令进行编译构建 make CC${CROSS_COM…...

langgraph简单Demo(使用langserve实现外部调用)

前言 这个示例是研究如何使用langserve实现外部调用 接入大模型参考文章&#xff1a;接入阿里云百炼 1、安装依赖 pip install langserve fastapi uvicorn pip install sse_starlette 2、代码实现 from fastapi import FastAPI from langchain_core.messages import HumanM…...

【C#高阶编程】—单例模式详解

C# 单例模式 单例模式是一种设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。单例模式常用于需要全局唯一对象的场景&#xff0c;比如配置文件管理、日志记录、数据库连接池等。 单例模式的核心特点 私有构造函数&#xff1a;…...

折叠树报表

折叠树报表中包含了三种信息: 1.树组织信息-可展开、收拢 2.节点的统计信息(汇总求和) 3.每个节点对应的数据信息 一、准备数据 mysql8 数据库中存在两张表 org和store表。 org表和部分数据如下,其中orgname是组织的名称,codepath是完整的组织代码,seq是每个节点的顺序,可…...

Python个人学习笔记(16):模块(os)

四、os模块 主要用于文件夹处理 &#xff08;一&#xff09;文件夹相关 os.makedirs(‘dirname1/dirname2’) &#xff1a;创建文件夹目录&#xff0c;不能重复创建&#xff0c;用的多 代码&#xff1a; os.makedirs(a/b/c)结果&#xff1a; os.removedirs(‘dirname1’)&…...

虚拟地址空间(下)进程地址空间(上)

一.关于页表组成 1.权限&#xff08;rwx) 作用&#xff1a;如1.让代码区变成只读的 2.写时拷贝的实现&#xff1a;子进程创建时其页表指向的父进程代码和数据权限都是只读的&#xff0c;子进程试图修改&#xff0c;触发错误&#xff0c;系统开始写时拷贝。 来源&#xff1a;…...

【数据集分享】青藏高原两次强震玛多地震和漾濞地震的震源过程

2021年5月21日&#xff0c;5小时内在青藏高原不同区域发生了漾濞6.4级和玛多7.4级强烈地震&#xff0c;表明印度板块和欧亚大陆板块的碰撞汇聚作用下青藏高原持续和频繁的 剧烈构造运动和地震活动。本研究利用地震记录和空间对地观测同震位移资料&#xff08;InSAR&#xff09;…...

jmeter环境搭建及使用

Meter 是一个开源的性能测试工具&#xff0c;用于测试静态和动态资源的性能。 1、安装 官网下载&#xff1a; 下载地址&#xff1a;Apache JMeter - Download Apache JMeter 网盘下载&#xff1a; 通过百度网盘分享的文件&#xff1a;apache-jmeter-5.6.3.rar 链接&#x…...

Python 鼠标轨迹算法 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…...

网络编程--服务器双客户端聊天

写一个服务器和客户端 运行服务器和2个客户端&#xff0c;实现聊天功能 客户端1和客户端2进行聊天&#xff0c;客户端1将聊天数据发送给服务器&#xff0c;服务器将聊天数据转发给客户端2 要求&#xff1a; 服务器使用 select 模型实现 &#xff0c;客户端1使用 poll 模型实现…...

yum软件包乾坤大挪移(Yum Package Qiankun Great Migration)

yum软件包乾坤大挪移 背景 由于很多的生产环境是无法连接外网的&#xff0c;因此用yum或者dnf命令来安装软件包常常是一个比较麻烦的事情&#xff0c;原因是很多软件的依赖很复杂&#xff0c;如果要一个个下载、拷贝、再安装&#xff0c;这往往是一个非常繁琐冗杂的过程&…...

Java:读取中文,read方法

public static void main(String[] args) throws IOException {FileReader fr new FileReader("C:\\aaa\\a.txt");//字符流的底层也是一个字节一个字节读取的&#xff0c;遇到中文就一次读多个&#xff0c;GBK一次读两个&#xff0c;UTF-8一次读三个字节//idea默认U…...

[GHCTF 2025]真会布置栈吗?

题目是一个聊天室,我们先按照题目使用 /help Help: /help 显示此帮助信息 /msg [text] 在当前频道发送消息 /nick [name] 更改你的用户名 /list 列出可用的频道 /join [channel] 切换到不同的频道 /channel …...

集合的练习1-2

//练习1&#xff1a; import java.util.ArrayList;public class ArraylistTest1 {public static void main(String[] args){ArrayList<String> listnew ArrayList<>();//需求&#xff1a;定义一个集合&#xff0c;添加字符串&#xff0c;并进行遍历//遍历格式&…...

英语词性--数词

文章目录 数词概念数词分词基数词序数词 基数与序数词的区别基变序的规律 数词概念 数词&#xff08;Numerals&#xff09; 是英语中用于表示 数量&#xff08;基数&#xff09;或顺序&#xff08;序数&#xff09; 的词类&#xff0c;通常用于描述数字、计数、顺序等。 例如&…...

面试整理--一个报告生成的方案解析

最近又快到了年后找工作的时间&#xff0c;近期写点工作积累&#xff0c;供大家参考。 欢迎关注公主号【测试开发备忘录】&#xff0c;交流职场技巧和经验 首先从工作中一个报错来展开: Start directory is not importable: 错误信息 "Start directory is not importable…...

C#零基础入门篇(18. 文件操作指南)

## 一、文件操作基础 在C#中&#xff0c;文件操作主要通过System.IO命名空间中的类来实现&#xff0c;例如File、FileStream、FileInfo等。 ## 二、常用文件操作方法 ### &#xff08;一&#xff09;文件读取 1. **使用File.ReadAllText方法读取文件内容为字符串** …...

Linux 一步部署DHCP服务

#!/bin/bash #脚本作者和日期 #author: PEI #date: 20250319 #检查root权限 if [ "$USER" ! "root" ]; then echo "错误&#xff1a;非root用户&#xff0c;权限不足&#xff01;" exit 0 fi #防火墙与高级权限 systemctl stop firewa…...

如何打造安全稳定的亚马逊采购测评自养号下单系统?

在当今的电商领域&#xff0c;亚马逊作为全球领先的在线购物平台&#xff0c;其商品种类繁多&#xff0c;用户基数庞大&#xff0c;成为了众多商家和消费者的首选。而对于一些需要进行商品测评或市场调研的用户来说&#xff0c;拥有一个稳定、安全的亚马逊账号体系显得尤为重要…...

【大模型学习】第二十四章 生成式人工智能(GAI)简介

目录 一、什么是生成式人工智能&#xff08;GAI&#xff09;&#xff1f;‌ 二、核心技术原理‌ ‌三、典型应用场景‌ ‌四、技术特点与挑战‌ 五、训练优化策略 六、关键性能指标&#xff08;2025年基准&#xff09; ‌七、技术演进方向‌&#xff1a; 一、什么是生成式…...

Pytorch中layernorm实现详解

平时我们在编写神经网络时&#xff0c;经常会用到layernorm这个函数来加快网络的收敛速度。那layernorm到底在哪个维度上进行归一化的呢&#xff1f; 一、问题描述 首先借用知乎上的一张图&#xff0c;原文写的也非常好&#xff0c;大家有空可以去阅读一下&#xff0c;链接放…...

YOLO11报错:AttributeError: module ‘torch‘ has no attribute ‘OutOfMemoryError‘

事情是这样的&#xff1a;前几天YOLO11的代码还是可以训练的&#xff0c;昨天训练了一天&#xff0c;今天换模型就报这个错。 AttributeError: module torch has no attribute OutOfMemoryError我查了一下&#xff1a;YOLO11官方代码issues里面也有人有同样的问题&#xff0c;…...

基于java的ssm+JSP+MYSQL的高校四六级报名管理系统(含LW+PPT+源码+系统演示视频+安装说明)

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…...

Starrocks 命令 Alter table DISTRIBUTED 重分布数据的实现

背景 在前文Starrocks 写入报错 primary key memory usage exceeds the limit中&#xff0c;可以通过ALTER TABLE xxxx DISTRIBUTED BY HASH(xx) BUCKETS 50;来改变数据的分布状态,具体的执行过程是怎么样的呢&#xff1f; 分析 首先对应的g4文件中为 alterTableStatement &…...

ns3使用入门_基于ns3.44_Part2_配置模块参数的Configuration 和Attributes

前言 事实上ns3的官方手册很全,相关书籍也是有的,官网先贴在这里: ns-3 | a discrete-event network simulator for internet systemsa discrete-event network simulator for internet systemshttps://www.nsnam.org/相关的脚本介绍也都有一些: ns-3.35_wifi-he-networ…...