【JS进阶】JS 迭代器和生成器

全网最完整的JavaScript迭代器(遍历器)整理长文,强烈建议收藏!!! 全网最完整的JavaScript迭代器(遍历器)整理长文. Iterator,for...in,for...of,for await... of,forEach(),map(),every(),some(),find(),findIndex(),filter(),reduce(),reduceRight() 迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 for...of不能遍历object对象 阅读详情

JS 迭代器和生成器

1.迭代器

迭代器,Iterator,其代表一种接口,目的是为各种不同的数据结构提供统一的访问机制。

任何数据结构,只要部署了 Iterator 接口,就可以完成遍历操作!(当然要是可遍历的数据结构,像 let、Number 这种不可遍历的自然就不支持迭代器了)

首先来了解三个相关的类型:

  • 可迭代对象 — 类似Array、NodeList等数据结构,当然我们也可以自己定义一个可迭代对象
  • 迭代器对象 — 是指任何具备next()方法的,且方法返回迭代结果对象的对象,其可以用于执行迭代。
  • 迭代器结果对象 — 指由next()方法返回的,具有属性value和done的对象,用于保存每次迭代的结果。

具体来说,当我们通过使用next()方法实现了一个符合迭代协议的对象时,这个对象就被称为迭代器对象。此时,next()方法会返回一个拥有属性value和done的对象,即迭代器结果对象。对于迭代器结果对象中的两个属性:value对应的是迭代时的next值;而done则是用于标识是否已经迭代到序列的最后一个值。

1.1 迭代协议

至于迭代协议 Iterator protocol ,官方文档中的大致意思是:

首先,迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。

迭代协议具体分为两个协议:可迭代协议和迭代器协议

可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。而要成为一个可迭代对象,需要实现**@@iterator** 方法,即一个名为 [Symbol.iterator] 的方法,该方法没有参数,其返回值为一个符合迭代器协议的对象。

当一个对象要被迭代时(例如被放入一个 for of 循环中时),会自动地调用它的**@@iterator** 方法,然后通过该方法返回的迭代器对象获取要迭代的值。

迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式,当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。简单来说,其定义了一个迭代器对象的实现标准,即:

  1. 该对象必须实现了一个**next()** 方法
  2. 该对象中所有迭代器协议的方法(next()、return() 和 throw())都应返回实现 IteratorResult 接口的对象,即拥有属性value和done的对象

至于更详细的内容,可以参阅官方文档。

1.2 哪些数据结构支持迭代器?

支持 Iterator 接口的数据结构有:

  1. String
  2. Array
  3. Map
  4. Set
  5. TypedArray
  6. 函数中的 arguments 对象
  7. DOM 中的 NodeList 对象

另外,需要注意的是,实际上我们也可以不使用这些数据结构,而是自己定义一个符合上面迭代协议的对象!

1.3 迭代器原理

根据上面的内容,我们可以发现,当我们迭代一个可迭代对象时,实际上是通过该对象身上的**@@iterator** 方法获得一个迭代器对象,然后重复地调用该迭代器对象中的**next()** 方法,而该方法会返回一个迭代器结果对象,其中包含了下一次迭代的值,以及一个标识是否结束的布尔值。重复操作直到该布尔值为 true 时,迭代就停止了。

1.4 迭代器的基本应用

对于可迭代对象,我们实际上并不用显示地调用**@@iterator** 方法,而是可以通过 for of、扩展操作符等直接操作!

// 通过 for of 操作可迭代对象
const Iterable = ['1', '2', '3', '234', '555'];
for (let v of Iterable) {
    console.log(v)	// '1', '2', '3', '234', '555'
}

// 通过扩展操作符操作可迭代对象
data = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(Math.max(...data)); 	// 8

另外,迭代器也可以用于 ES6 中的解构赋值:

let arr = [10 , 18 , 20];
let [a , b , c] = arr;
console.log(c);		// 20
1.5 自定义的可迭代对象

根据前面的内容,要实现一个可迭代对象,首先需要实现**@@iterator** 方法,其需要返回一个内置了**next()** 方法的迭代器对象。next() 方法需要能够实现迭代,并返回一个拥有属性value和done的迭代器结果对象。

因此,实现如下:

const myIterable = {
  name: 'my iterable obj',
  data: ['test1', 'iterable', '222', 'test2', 'ababab'],
  // 迭代器方法
  [Symbol.iterator]() {
    // 索引
    let index = 0;
    // 返回一个迭代器对象
    return {
      // next()方法
      next: () => {
        if (index < this.data.length) {
          const res = {
            value: this.data[index],
            done: false,
          };
          index++;
          return res;
        } else {
          return {
            value: undefined,
            done: true,
          };
        }
      },
    };
  },
};

// 通过 for of 遍历该可迭代对象
for (let v of myIterable) {
    console.log(v)	// 'test1', 'iterable', '222', 'test2', 'ababab'
}

2.生成器

2.1 生成器的基本概念和基本原理

生成器,在官方文档中的描述是这样的:

生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态。

生成器同时也是一种异步编程解决方案。

生成器函数使用**function***语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为 Generator 的迭代器。

而通过调用生成器的**next()**方法消耗值时,生成器函数才会执行,并一直运行直到遇到 yield 关键字。即,第一次调用next()方法时,生成器函数会一直执行到其代码中的第一个 yield 关键字处;第二次调用next()方法时,生成器函数会从第一个 yield 关键字处执行到第二个 yield 关键字处。

下面是一个例子:

// 定义一个生成器函数
function* fn() {
    console.log('生成器函数第一次执行');
    yield 'result1';
    console.log('生成器函数第二次执行');
    yield 'result2';
    console.log('生成器函数第三次执行');
    yield 'result3';
    console.log('生成器函数第四次执行');
}

// 调用生成器函数,得到一个生成器对象
let gen = fn()	// 此处生成器函数内部的代码并不会执行!仅仅是得到了一个生成器对象

// 调用生成器对象的next()方法
console.log(gen.next())	// 生成器函数第一次执行 {value: 'result1', done: false}
console.log(gen.next())	// 生成器函数第二次执行 {value: 'result2', done: false}
console.log(gen.next())	// 生成器函数第三次执行 {value: 'result3', done: false}
console.log(gen.next())	// 生成器函数第四次执行 {value: undefined, done: true}

可以看到,第一次调用next()方法时,生成器函数内部的代码仅执行到第一个 yield 关键字处,并将 yield 关键字后表达式的值作为next()方法所返回的迭代器结果对象中value的值!

而第二次调用next()方法时,则是从第一个 yield 关键字后开始执行,直到遇到第二个 yield 关键字,并同样地将yield 关键字后表达式的值作为next()方法所返回的迭代器结果对象中value的值返回出去…重复此操作,直到最后一次调用next()方法,此时从最后一个 yield 关键字后开始执行,直到函数结束,且此时返回的值中,value的值为undefined,而done的值为true,说明迭代已经结束!

2.2 生成器函数中的yield

通过上面的例子,我们可以了解到,执行next()方法后,生成器函数会将某一个yield关键字后面的表达式的值作为next()方法的返回值,并将函数暂停在yield关键字处。

而上面的例子中没有提及的是,如果我们在调用next()方法时,传入参数,那么我们传入的参数会变成上一次暂停处的yield表达式的值!

下面通过一个例子来理解:

// 定义一个生成器函数
function* fn(str) {
    console.log(str); 
    let a = yield 1;  // 第一次调用暂停的位置
    console.log(a);   
    let b = yield 2;  // 第二次调用暂停的位置
    console.log(b);  
    let c = yield 3;  // 第三次调用暂停的位置
    console.log(c);
    return 100
}

// 获取生成器对象
let gen = fn('测试传参')

// 第一次调用next方法,传入一个参数 'a'
console.log(gen.next('a'))
// 此时是第一次调用,该参数会被丢弃,因为没有上一次暂停处!
// 执行结果为:测试传参 {value: 1, done: false}

// 第二次调用,传入一个参数 'b'
console.log(gen.next('b'))
// 此时有上一次调用暂停的位置:let a = yield 1;
// 此时 'yield 1' 整个表达式的值被赋为我们传入的参数 'b'
// 因此本次的执行结果为:b {value: 2, done: false}

// 第三次调用,传入一个参数 'c'
console.log(gen.next('c'))
// 与上面同理,上一次暂停位置的yield表达式 'yield 2' 的值被赋为 'c'
// 所以本次执行结果为:c {value: 3, done: false}

// 最后一次调用,传入参数 'd'
console.log(gen.next('d'))
// 还是同理,'yield 3' 的值被赋为 'd',另外,生成器函数中有return,所以这里迭代器结果对象中的value有值了
// d {value: 100, done: false}

2.3 生成器的应用 — 模拟异步问题
function fa() {
    setTimeout(() => {
        let yon = '用户数据';
        //传入参数并调用
        han.next(yon);
    }, 1000);
}

function fb() {
    setTimeout(() => {
        let din = '订单数据';
        han.next(din);
    }, 1000);
}

function fc() {
    setTimeout(() => {
        let shang = '商品数据';
        han.next(shang);
    }, 1000);
}

function* fn() {
    let a = yield fa();
    console.log(a);        //1s 用户数据
    let b = yield fb();
    console.log(b);        //2s 订单数据
    let c = yield fc();
    console.log(c);        //3s 商品数据
}
let han = fn();
//调用
han.next();

总的来说,生成器是ES6中提供的一种异步编程的解决方法,但通过上面的例子可以看到,单纯地利用生成器来实现异步操作,会导致代码可读性比较低,在实际开发中使用更多的还是 async/await 和 promise 。

JavaScript 中的迭代器、生成器与可迭代对象:深入理解遍历机制 迭代器是一个对象,它提供了一种标准的方式来遍历集合中的元素。迭代器对象必须实现一个next()value:当前遍历的值。done:一个布尔值,表示遍历是否结束。} else {// 输出: 1, 2, 3, 4, 5myIterable是一个可迭代对象,因为它实现了方法。方法返回一个迭代器对象,该对象实现了next()方法。next()方法每次返回一个值,直到遍历结束。生成器是一种特殊的函数,通过function*关键字定义。 阅读详情

相关推荐

CentOS校园网Web Portal认证自动化实战

Web Portal认证是一种基于HTTP重定向与表单提交的强制网络准入机制,其原理是网关劫持未认证流量并跳转至登录页,验证通过后通过Cookie维持会话授权。该技术广泛应用于高校、机场、酒店等场景,核心价值在于细粒度访问控制与用户身份绑定。典型应用包括Linux命令行环境下的校园网接入、无GUI设备的自动联网、以及实验室集群的集中认证管理。本文聚焦CentOS系统,深入解析curl、cookie持久化、动态表单参数提取等关键技术环节,提供可调试、可复现、可工程化的完整认证流水线。

weixin_30522983的博客 265

JS的迭代器

在JavaScript中,迭代器(Iterator)是一种遍历任何可迭代对象(Iterable)的通用接口。迭代器是ES6规范中引入的一种新的数据类型,用于遍历各种数据结构,包括数组、对象、Map、Set等。在语言层面上,迭代器可以被看做一个有next方法的对象,每次调用next方法都可以返回一个值对象(Value)和一个布尔值(Done),表示是否遍历结束。其中,Value代表当前迭代项的取值,Done代表迭代是否结束。

一步一个脚印,踏实努力,向着目标前进 3648

中职网络安全2021年国赛Wireshark流量分析题目解析

中职网络安全Wireshark流量分析题目解析

FRANXX_02的博客 6441

JS - iterator(迭代器)

这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这个对象有 value 和 done 两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否有必要再调用一次next ()。其次,Set结构遍历时,返回的是一个值。而Map结构遍历时,返回的是一个数组,该数组的两个成员分别是当前Map成员的键名和键值。实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。

m0_52545254的博客 6854

基于MYD-YT153与AD7616的16通道高速ADC采集系统实战指南

在嵌入式系统与工业数据采集领域,模拟信号采集是连接物理世界与数字系统的关键技术。其核心原理是通过模数转换器(ADC)将连续的模拟电压信号转换为离散的数字码值,供处理器处理。这项技术的价值在于实现了对温度、压力、振动等关键物理量的精确感知与数字化,是工业自动化、设备监测、科学实验等场景的基石。本文聚焦于**多通道**、**高精度**采集这一常见需求,深入剖析如何利用全志T153处理器的LocalBus并行总线接口,高效驱动ADI的16位、16通道同步采样ADC芯片AD7616,构建一个稳定可靠的高速数据采集系

weixin_30335353的博客 443

Python实战:5分钟搞定高德地图API批量地址转经纬度(附完整代码)

本文提供了一套完整的Python解决方案,利用高德地图Web服务API,实现批量地址到经纬度坐标的自动化转换。文章包含从API申请、核心代码编写到错误处理与性能优化的全流程实战指南,并附赠数据可视化方法,帮助数据分析师和开发者快速提升地理信息处理效率。

weixin_29047919的博客 582

JS的迭代器和可迭代对象详解

迭代器(iterator),是使用户在容器对象(container,例如链表或数组)上可以遍历访问的对象,使用该接口无需关心容器对象的内部实现细节。从迭代器的定义我们可以看出来,迭代器是帮助我们对某个数据结构进行遍历的对象。在JavaScript中,迭代器也是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol):next方法要求:next方法是一个无参数或者有一个参数的函数,返回结果应当拥有以下两个属性的对象:1.done(boolean) : done返回一个布尔值: 可能是

m0_71485750的博客 5548

KEIL5编译报错L6200E:__stdout重定义问题分析与解决

本文深入分析KEIL5编译报错L6200E中__stdout重定义问题的根源,指出因未完整定义__stderr导致与标准库stdio_streams.o冲突。提供完整重定义标准流、启用MicroLIB库等解决方案,帮助开发者彻底解决Symbol multiply defined错误,提升嵌入式开发效率。

uran的专栏 954

JavaScript进阶——05-迭代器和生成器【万字长文,感谢支持】

在面向对象开发时,如果你希望自己创建的类也具备可迭代的能力,那么,你可以在定义类的时候手动添加一个@@iterator方法,让其成为可迭代对象。代码举例:// 定义类// 定义一个名为 [Symbol.iterator] 的实例方法,封装迭代器} else {},const person1 = new Person('千古壹号', ['前端', '工程师']);const person2 = new Person('许嵩', ['想象之中', '有何不可']);

——心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,谦虚,自律,反思,成长,还算是比较正能量的博主,公益免费传播……内心特别想在AI界做出一些可以推进历史进程影响力的东西(兴趣使然,有点小情怀,也有点使命感呀)… 1322

基于Simulink的电机热阻模型建立与仿真

本文详细介绍了基于Simulink的电机热阻模型建立方法。通过将电机传热路径分解为5段关键热阻(绕组内部、槽绝缘、铁芯、机壳、冷却系统),采用Simscape Thermal模块构建热阻网络模型。重点阐述了参数化热阻计算、实验数据校准、不同设计方案对比等关键步骤,并以15kW车用PMSM为例演示建模过程。文章还分享了非线性热阻处理、多维网络构建等高级技巧,指出该模型在热设计迭代、散热匹配、故障诊断等方面的重要工程价值,为电机热安全设计提供了有效的数字化解决方案。

xiaoheshang_123的博客 335

全能媒体工具深度测评(下篇一):AI图文生成+全能解压+图片去文字,一键搞定素材精修

解压50多种格式,文生图,图生图

cs821984831的博客 40

ES6-----迭代器和生成器

一、迭代器 迭代器是一个对象,具有一些专门为迭代过程设计的专有接口。所有的迭代器对象都有一个next()方法,每次调用都会返回一个结果对象。结果对象中包含两个属性:value和done;其中value是每次迭代的返回的数据,done表示迭代是否结束(Boolean) 根据上面关于迭代器的描述,我们来模拟一下: function createIterator(items) { var ...

Caroline的博客 335

23、电器元件符号及封装大全(2025版本)

总计28类电器元件符号和封装。

XU157303764的博客 2652

JavaScript中的Generator和Async Iterators

主要总结JavaScript中Generator和Async Iterators的核心概念、使用场景、进阶技巧及注意事项等内容。

热爱前端的大宝同学。 2169

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

JS【实用教程】JavaScript(2025最新版)

JavaScript 简称 JS,可运行于浏览器 或 node 环境。

朝阳39的博客 2082

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

JavaScript性能优化实战:生成器与迭代器——控制任务执行流程

本文探讨了JavaScript生成器与迭代器在性能优化中的实战应用。通过惰性求值和分段执行机制,它们能有效解决同步阻塞、内存溢出和并发风暴等性能瓶颈。文章详细解析了生成器与迭代器的实现原理,并提供了三个核心优化场景:流式大数据渲染采用分块处理,高并发请求通过可控并发数调度,动画序列利用生成器编排保持帧率稳定。此外,还介绍了内存管理、V8优化技巧等底层原理,以及状态机、协程调度等进阶模式。

qinzhenyan的博客 1172

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

JS问题整理

JS中迭代器和生成器 for..in迭代的是对象的键的列表,而for..of则迭代对象的键对应的值。 JS中的闭包 https://www.jianshu.com/p/26c81fde22fb JS中的事件循环机制 https://blog.youkuaiyun.com/qq_39207948/article/details/81671304 JS promise https://www.c...

qq_28180261的博客 156

js 教程

关于javascript高级程序设计的相关读书笔记:学习思维导图​ 基础内容: HTML中的JavaScript 语言基础 变量、作用域与内存 基本引用类型 集合引用类型 进阶操作: 迭代器与生成器 对象、类与面向对象编程 代理与反射 函数 期约与异步函数 BOM和DOM BOM 客户端检测 DOM DOM扩展 DOM2和DOM3 事件 动画与Canvas图形 表单脚本 JavaScirpt API JavaScript API 错误处理与调试 处理XML JSON 网络请求与远程资源 客户端存储...

逆水寒 236

手写JavaScript函数式编程和异步编程底层代码

1.call实现 Function.prototype.$call = function(context, ...args) { // 调用者检查 if(typeof this !== "function") throw new TypeError("必须使用函数调用$call方法") // 上下文检查 context = context || globalThis context = context instanceof Object ? cont

qq_37464878的博客 953

~【笔记】黑马js高级和尚硅谷ES6笔记(部分)~

第一章

weixin_55935744的博客 4088

python中单双三引号区别_python基础题

1.简述列举了解的编程语言及语言之间的区别?解释型语言:python,javaScript,Shell执行的时候在翻译优点:开发效率高,缺点:运行速度慢编译型:c,c++只翻译一次优点:运行速度快缺点:开发效率低2,列举python2与python3的区别python2:print 变量 不需要加括号python3:print(变量)python2:两种整型 整形(int)和长整型(long)...

weixin_39588419的博客 195

【JS进阶】迭代器与生成器

这篇文章将介绍了ES6语法中迭代器和生成器的概念

Bl_a_ck的博客 1187

JavaScript进阶之(七) 迭代器与生成器

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators

火柴盒 434

JavaScript进阶讲解十七—>迭代器与生成器

迭代器(iterator) 迭代器(iterator),是确使用户可在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。 迭代器是帮助我们对某个数据结构进行遍历的对象 在JavaScript中,迭代器也是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol): 迭代器协议定义了产生一系列值(无论是有限还是无限个)的标准方式 在js中这个标准就是一个特定的next方法 next方法有如下的要求: 一个无参数或者一个参数的函数(如

wangyuiba1314的博客 279

JS进阶3-迭代器 生成器

迭代器 生成器

weixin_40746230的博客 292

JavaScript 异步 迭代器与生成器(Iterators & Generators

JavaScript迭代器与生成器深度指南 本文系统讲解了JavaScript迭代器和生成器的核心概念与应用。

wyp20151314的博客 507
上一篇: 【Git】Git cherry-pick
下一篇: 【CSS】position
cannotbecounted
博客等级 码龄7年 101粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值