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

JS【详解】迭代器 Iterator(含可迭代对象、同步迭代器、异步迭代器等)

什么是迭代器?

JS 迭代器是一种遍历访问数据结构中所有成员的机制,本质是一个指针对象。

为什么要有迭代器?

  • 为各种不同的数据结构提供统一的访问机制。
  • 自定义数据结构的遍历:当你创建了一个自定义的数据结构时,可以实现迭代器来方便地遍历其中的元素。
  • 惰性计算:迭代器可以实现惰性计算,即只有在需要时才计算下一个值,这样可以节省内存和计算资源。
  • 异步迭代器,可以用于处理异步数据流。

迭代器的遍历过程

  • 创建一个指针对象,指向数据结构的起始位置。

  • 第一次调用指针对象的 next 方法,指针指向数据结构的第一个成员。

  • 第二次调用指针对象的 next 方法,指针指向数据结构的第二个成员。

  • 依此类推,不断调用指针对象的 next 方法……

  • 当指针指向数据结构的结束位置,遍历结束

可迭代对象

实现了迭代器的对象(拥有返回一个具备 next 方法的 Symbol.iterator 方法),被称为可迭代对象(如字符串、数组、Set、Map 、Object 等),可通过 for…of 语句遍历。

Symbol.iterator 是一个 Symbol 类型的值,它是 JavaScript 内置的一个特殊 Symbol,用来表示对象的迭代器方法。由于它是 Symbol 类型而非普通字符串,所以不能直接当作静态属性名来使用,而需要通过计算属性名的方式来定义或访问(即需要用 [] 包裹使用)。

可迭代对象调用其 Symbol.iterator 方法会得到一个用于遍历该对象元素的迭代器。

const arr = [1, 2];
const iterator = arr[Symbol.iterator]();console.log(iterator.next());  // { value: 1, done: false }
console.log(iterator.next());  // { value: 2, done: false }
console.log(iterator.next());  // { value: undefined, done: true }

内置可迭代对象

JS 内置实现了迭代器的对象(具有 Symbol.iterator 属性)有:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

自定义可迭代对象

// 创建一个可迭代对象
const myIteratorObject = {data: [1, 2, 3, 4, 5],[Symbol.iterator]() {let index = 0;return {next: () => {if (index < this.data.length) {return { value: this.data[index++], done: false };} else {return { done: true };}}};}
};// 使用 for...of 循环遍历自定义的可迭代对象
for (const value of myIteratorObject) {console.log(value);
}

触发迭代器的场景

  • for…of 循环

  • 对数组和 Set 结构进行解构赋值

  • 扩展运算符(…)

  • yield*
    可迭代对象在 yield* 后时,会触发迭代器

    let generator = function* () {yield 1;yield* [2,3,4];yield 5;
    };var iterator = generator();iterator.next() // { value: 1, done: false }
    iterator.next() // { value: 2, done: false }
    iterator.next() // { value: 3, done: false }
    iterator.next() // { value: 4, done: false }
    iterator.next() // { value: 5, done: false }
    iterator.next() // { value: undefined, done: true }
    
  • Array.from()

  • Map(), Set(), WeakMap(), WeakSet()(比如new Map([[‘a’,1],[‘b’,2]]))

  • Promise.all()

  • Promise.race()

可迭代对象转数组

只要某个数据结构实现了迭代器,就可以对它使用扩展运算符,将其转为数组。

let arr = [...iterable];

return()方法

可迭代对象除了具有next()方法,还可以具有return()方法,但可以选择性实现。

如果for…of循环提前退出(通常是因为出错,或者有break语句),就会调用return()方法。

如果一个对象在完成遍历前,需要清理或释放资源,就可以通过return()方法。

return()方法必须返回一个对象

function readLinesSync(file) {return {[Symbol.iterator]() {return {next() {return { done: false };},return() {file.close();return { done: true };}};},};
}

下面的两种情况,都会触发执行return()方法。

// 情况一
for (let line of readLinesSync(fileName)) {console.log(line);break;
}// 情况二
for (let line of readLinesSync(fileName)) {console.log(line);throw new Error();
}

同步迭代器

迭代器有 next 方法,返回一个包含 value 和 done 两个属性的对象。

  • value 属性:当前迭代位置的值,可为任意类型( TS 中为 any) 。(即当前指针指向的数据结构的成员),当值为 undefined 时可省略。
  • done 属性:是否已迭代结束,布尔值,true 表明迭代结束,false 则意味着还有成员可供迭代,当值为 false 时可省略。
// 自定义迭代器
const myIterator = {// 需要遍历的成员data:[1,2,3],// 因第一个元素下标为 0 ,起始位置从 -1 开始index: -1,// 迭代器的核心方法 next next() {this.index++;// next 方法返回一个包含 value 和 done 两个属性的对象return {value: this.data[this.index], done:  this.index === this.data.length };},// 为了后续可用 for of 语句遍历,详见下文中可迭代对象的解析[Symbol.iterator]() {return this;},
};for (const item of myIterator) {console.log(item);  //1 2 3
}

异步迭代器

异步迭代器和同步迭代器相似,主要用于处理异步数据。

其 next 方法返回一个 Promise,该 Promise 会解析为一个包含 value 和 done 属性的对象。

// 定义异步迭代器
const asyncNumberIterator = {current: 0,max: 3,async next() {// 模拟异步操作await new Promise(resolve => setTimeout(resolve, 1000));if (this.current <= this.max) {const value = this.current++;return { value, done: false };}return { done: true };},[Symbol.asyncIterator]() {return this;}
};// 使用异步迭代器,需用 for await of
(async () => {for await (const num of asyncNumberIterator) {console.log(num);}
})();

TS 给迭代器标注类型

// 迭代器接口
interface Iterable {[Symbol.iterator]() : Iterator,
}// 迭代器指针
interface Iterator {next(value?: any) : IterationResult,
}// next 的返回值
interface IterationResult {value: any,done: boolean,
}

使用生成器实现迭代器

用 yield 命令给出每一步的返回值即可。

let obj = {* [Symbol.iterator]() {yield 'hello';yield 'world';}
};for (let x of obj) {console.log(x);
}
// "hello"
// "world"

【实战】迭代器实现“链表”结构

function Obj(value) {this.value = value;this.next = null;
}Obj.prototype[Symbol.iterator] = function() {var iterator = { next: next };var current = this;function next() {if (current) {var value = current.value;current = current.next;return { done: false, value: value };}return { done: true };}return iterator;
}var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);one.next = two;
two.next = three;for (var i of one){console.log(i); // 1, 2, 3
}

【实战】类似数组的对象实现迭代器

存在数值键名和length属性的对象为类似数组的对象。

将其 Symbol.iterator方法直接引用数组的 Iterator 接口可快捷实现迭代器

let iterable = {0: 'a',1: 'b',2: 'c',length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {console.log(item); // 'a', 'b', 'c'
}

相关文章:

JS【详解】迭代器 Iterator(含可迭代对象、同步迭代器、异步迭代器等)

什么是迭代器&#xff1f; JS 迭代器是一种遍历访问数据结构中所有成员的机制&#xff0c;本质是一个指针对象。 为什么要有迭代器&#xff1f; 为各种不同的数据结构提供统一的访问机制。自定义数据结构的遍历&#xff1a;当你创建了一个自定义的数据结构时&#xff0c;可以实…...

CFS 调度器两种调度类型普通调度 和 组调度

在 Linux 的 CFS&#xff08;Completely Fair Scheduler&#xff09; 调度器中&#xff0c;确实存在两种调度类型&#xff1a;普通调度 和 组调度。这两种调度类型分别适用于不同的场景&#xff0c;并通过三个关键维度&#xff08;权重、抢占优先级、最大配额&#xff09;来影响…...

Linux网络编程——详解网络层IP协议、网段划分、路由

目录 一、前言 二、IP协议的认识 1、什么是IP协议&#xff1f; 2、IP协议报头 三、网段划分 1、初步认识IP与路由 2、IP地址 I、DHCP动态主机配置协议 3、IP地址的划分 I、CIDR设计 II、子网数目的计算 III、子网掩码的确定 四、特殊的IP地址 五、IP地址的数量限…...

【图像生成之21】融合了Transformer与Diffusion,Meta新作Transfusion实现图像与语言大一统

论文&#xff1a;Transfusion: Predict the Next Token and Diffuse Images with One Multi-Modal Model 地址&#xff1a;https://arxiv.org/abs/2408.11039 类型&#xff1a;理解与生成 Transfusion模型‌是一种将Transformer和Diffusion模型融合的多模态模型&#xff0c;旨…...

Microsoft Office 如何启用和正常播放 Flash 控件

对于新安装的 Office 默认是不支持启用 Flash 组件的&#xff0c;Flash 组件会无法播放或者黑屏。 本片文章就带你解决这个问题&#xff0c;相关资料都在下方连接内。前提概要&#xff0c;教程对应的版本是 mso16&#xff0c;即 Office 2016 及更新版本&#xff0c;以及 365 等…...

深入浅出:信号灯与系统V信号灯的实现与应用

深入浅出&#xff1a;信号灯与系统V信号灯的实现与应用 信号灯&#xff08;Semaphore&#xff09;是一种同步机制&#xff0c;用于控制对共享资源的访问。在多线程或多进程环境下&#xff0c;信号灯能够帮助协调多个执行单元对共享资源的访问&#xff0c;确保数据一致性与程序…...

定位改了IP属地没变怎么回事?一文解析

明明用虚拟定位软件将手机位置改到了“三亚”&#xff0c;为何某某应用评论区显示的IP属地还是“北京”&#xff1f;为什么切换了代理IP&#xff0c;平台却似乎“无视”这一变化&#xff1f; 在“IP属地显示”功能普及后&#xff0c;许多用户尝试通过技术手段隐藏真实位置&…...

Cygwin中使用其它平台生成的动态库

在 Cygwin 环境下链接 VC 生成的 DLL 库需解决符号导出格式和调用约定的兼容性问题&#xff0c;以下是具体操作步骤&#xff1a; 一、VC 生成 DLL 的配置要点 ‌声明 C 风格导出函数‌ 在 VC 中使用 extern "C" 和 __declspec(dllexport) 避免 C 名称修饰&#xff0c…...

《深入理解生命周期与作用域:以C语言为例》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、生命周期&#xff1a;变量的存在时间&#xff08;一&#xff09;生命周期的定义&#xff08;二&#xff09;C语言中的生命周期类型&#xff08;三&#…...

算法魅力揭秘:螺旋矩阵 II 的模拟填充与规则总结

算法魅力揭秘&#xff1a;螺旋矩阵 II 的模拟填充与规则总结 作为一个算法人&#xff0c;我们经常在竞赛和面试中遇到各种“矩阵类”问题&#xff0c;而螺旋矩阵 II 是其中一颗耀眼的明星。今天我将带大家从直观理解到实战代码&#xff0c;全面拆解螺旋矩阵 II 的规律与实现。…...

一个插件,免费使用所有顶级大模型(Deepseek,Gpt,Grok,Gemini)

DeepSider是一款集成于浏览器侧边栏的AI对话工具&#xff0c;可免费使用所有顶级大模型 包括GPT-4o&#xff0c;Grok3,Claude 3.5 Sonnet,Claude 3.7,Gemini 2.0&#xff0c;Deepseek R1满血版等 以极简交互与超快的响应速度&#xff0c;完成AI搜索、实时问答、内容创作、翻译、…...

springboot Filter实现请求响应全链路拦截!完整日志监控方案​​

一、为什么你需要这个过滤器&#xff1f;​​ 日志痛点&#xff1a; &#x1f6a8; 请求参数散落在各处&#xff1f; &#x1f6a8; 响应数据无法统一记录&#xff1f; &#x1f6a8; 日志与业务代码严重耦合&#xff1f; ​​解决方案​​&#xff1a; 一个Filter同时拦截请…...

智能车摄像头开源—9 动态权、模糊PID、速度决策、路径优化

目录 一、前言 二、动态权 1.概述 2.偏差值加动态权 三、模糊PID 四、速度决策 1.曲率计算 2.速度拟合 3.速度控制 五、路径 六、国赛视频 一、前言 在前中期通过识别直道、弯道等元素可进行加减速操作实现速度的控制&#xff0c;可进一步缩减一圈的运行速度&#xff…...

《2025蓝桥杯C++B组:D:产值调整》

**作者的个人gitee**​​ 作者的算法讲解主页▶️ 每日一言&#xff1a;“泪眼问花花不语&#xff0c;乱红飞过秋千去&#x1f338;&#x1f338;” 题目 二.解题策略 本题比较简单&#xff0c;我的思路是写三个函数分别计算黄金白银铜一次新产值&#xff0c;通过k次循环即可获…...

蓝队技能-Web入侵-入口查杀攻击链

Web攻击事件 分析思路&#xff1a; 1、利用时间节点筛选日志行为 2、利用对漏洞进行筛选日志行为 3、利用后门查杀进行筛选日志行为 4、利用文件修改时间筛选日志行为 Web日志分析 明确存储路径以及查看细节 常见中间件存储路径 IIS、Apache、Tomcat 等中间件的日志存放目…...

Android11车载WiFi热点默认名称及密码配置

一、背景 基于车厂信息安全要求,车载热点默认名称不能使用统一的名称,以及默认密码不能为简单的1~9。 基于旧项目经验,组装工厂自动化测试及客户整车组装的时候均存在多台设备同时打开,亦不太推荐使用统一的热点名称,连接无法区分。 二、需求 根据客户的要求,默认名称…...

对于GAI虚假信息对舆论观察分析

摘要 生成式人工智能&#xff08;Generative Artificial Intelligence, GAI&#xff09;的技术革新重构了信息生产机制&#xff0c;但也加剧了虚假信息对舆论生态的异化风险。 关键词&#xff1a;生成式人工智能、虚假信息、舆论异化、智能治理 一、生成式人工智能虚假信息下…...

问题 | 对于初学者来说,esp32和stm32哪个比较适合?

对于初学者选择ESP32还是STM32入门嵌入式开发&#xff0c;需综合考虑学习目标、兴趣方向及未来职业规划。以下是两者的对比分析及建议&#xff1a; 1. 适合初学者的关键因素 ESP32的优势 内置无线通信&#xff1a;集成Wi-Fi和蓝牙功能&#xff0c;无需额外模块即可开发物联网…...

grafana/loki 部署搜集 k8s 集群日志

grafana/loki 和 grafana/loki-stack 的区别 ​Grafana 提供了多个 Helm Chart 用于在 Kubernetes 集群中部署 Loki 及相关组件,其中主要包括 grafana/loki 和 grafana/loki-stack。​它们的主要区别如下:​ 1.grafana/loki Helm Chart: 专注于 Loki 部署: 该 Chart 专门…...

EN控制同步整流WD1020 ,3.0V-21V 的宽 VIN 输入范围,0.9V-20V 的宽输出电压范围

WD1020 是一款功能强大且性能卓越的电源管理芯片&#xff0c;凭借其独特的特点在众多电子设备领域中展现出广泛的应用前景。以下是对其特点和应用电路的详细阐述&#xff1a; 集成式功率 MOSFET&#xff1a;WD1020 集成了低 RDS&#xff08;开&#xff09;功率 MOSFET&#xff…...

asm汇编语言源代码之-获取环境变量

提供1个子程序: 1. 读取环境变量 GETENVSTR 具体功能及参数描述如下 GETENVSTR PROC FAR ;IN: DSPSP SEG. ;   ES:BX -> ENV VAR NAME ;OUT: DS:DX -> ENV VAR VALUE; IF DX0FFFFH, NOT FOUND   ; more source code at http://www.ahjoe.com/source/srcdown.aspPU…...

2025认证杯一阶段各题需要使用的模型或算法(冲刺阶段)

A题&#xff08;小行星轨迹预测&#xff09; 问题一&#xff1a;三角测量法、最小二乘法、空间几何算法、最优化方法 问题二&#xff1a;Gauss/Laplace轨道确定方法、差分校正法、数值积分算法&#xff08;如Runge-Kutta法&#xff09;、卡尔曼滤波器 B题&#xff08;谣言在…...

①(PROFINET 转 EtherNet/IP)EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

型号 协议转换通信网关 PROFINET 转 EtherNet/IP MS-GW32 概述 MS-GW32 是 PROFINET 和 EtherNet/IP 协议转换网关&#xff0c;为用户提供两种不同通讯协议的 PLC 进行数据交互的解决方案&#xff0c;可以轻松容易将 EtherNet/IP 网络接入 PROFINET 网络中&#xff0c;方便…...

LeetCode 3272.统计好整数的数目:枚举+排列组合+哈希表

【LetMeFly】3272.统计好整数的数目&#xff1a;枚举排列组合哈希表 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-the-count-of-good-integers/ 给你两个 正 整数 n 和 k 。 如果一个整数 x 满足以下条件&#xff0c;那么它被称为 k 回文 整数 。 x 是一个…...

Linux中的tar -P选项

tar -P选项 Linux中的tar命令可用于文件和目录的归档以及压缩解压缩。而其中的-P选项是什么含义呢&#xff1f;下面我们就来看一看 1、不添加-P选项 对于如下压缩命令&#xff1a; tar -czvf pkg.tar.gz /opt/software执行该命名&#xff0c;控制台首行输出将会提示&#xf…...

Linux目录探秘:文件系统的核心架构

引言 Linux文件系统就像一棵精心设计的大树&#x1f333;&#xff0c;每个分支都有其特定的用途和规范。与Windows不同&#xff0c;Linux采用单一的目录结构&#xff0c;所有设备、分区和网络资源都挂载在这个统一的目录树下。本文将带你深入探索Linux目录结构的奥秘&#xff…...

国标GB28181视频平台EasyCVR如何搭建汽车修理厂远程视频网络监控方案

一、背景分析 近年我国汽车保有量持续攀升&#xff0c;与之相伴的汽车保养维修需求也逐渐提高。随着社会经济的发展&#xff0c;消费者对汽车维修服务质量的要求越来越高&#xff0c;这使得汽车维修店的安全防范与人员管理问题面临着巨大挑战。 多数汽车维修店分布分散&#…...

python【标准库】multiprocessing

文章目录 介绍多进程Process 创建子进程共享内存数据多进程通信Pool创建子进程多进程案例多进程注意事项介绍 python3.10.17版本multiprocessing 是一个多进程标准模块,使用类似于threading模块的API创建子进程,充分利用多核CPU来并行处理任务。提供本地、远程的并发,高效避…...

南墙WAF非标端口防护实战解析——指定端口安全策略深度剖析

本文系统解析非标端口DDoS攻击防护难点&#xff0c;重点阐述南墙WAF在指定端口防御中的技术突破。通过某金融机构真实攻防案例&#xff0c;结合Gartner最新防御架构模型&#xff0c;揭示如何构建基于智能流量建模的精准防护体系&#xff0c;为金融、政务等关键领域提供可落地的…...

PostIn安装及入门教程

PostIn是一款国产开源免费的接口管理工具&#xff0c;包含项目管理、接口调试、接口文档设计、接口数据MOCK等模块&#xff0c;支持常见的HTTP协议、websocket协议等&#xff0c;支持免登陆本地接口调试&#xff0c;本文将介绍如何快速安装配置及入门使用教程。 1、安装 私有…...