JS中迭代器的介绍

1、简介

  • 迭代器(iterator),使用户在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。
  • 迭代器(iterator)是一个结构化的模式,用于从源以一次一个的方式提取数据。
  • 迭代器是一种有序的、连续的、基于拉取的用于消耗数据的组织方式。

2、接口

Iterator [required]next() {method}: 取得下一个IteratorResult

有些迭代器还扩展支持两个可选成员:

Iterator [optional]return() {method}: 停止迭代器并返回IteratorResultthrow() {method}: 报错并返回IteratorResult

IteratorResult 接口指定如下:

IteratorResultvalue {property}: 当前迭代值或者最终返回值(如果undefined为可选的)done {property}: 布尔值,指示完成状态

还有一个 Iterable 接口,用来表述必需能够提供生成器的对象:

Iterable@@iterator() {method}: 产生一个 Iterator

3、next()迭代

我们来观察一个数组,这是一个 iterable,它产生的迭代器可以消耗其自身值:

var arr = [1,2,3];
var it = arr[Symbol.iterator]();
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 3, done: false }
it.next(); // { value: undefined, done: true }

前面代码中在提取值 3 的时候,迭代器 it 不会报告 done: true。必须得再次调用 next(),越过数组结尾的值,才能得到完成信号 done: true。虽然直到本小节的后面才会介绍原因,但这样的设计决策通常被认为是最佳实践。

基本字符串值默认也可以迭代:

var greeting = "hello world";
var it = greeting[Symbol.iterator]();
it.next(); // { value: "h", done: false }
it.next(); // { value: "e", done: false }
..

严格来说,基本值本身不是 iterable,但是感谢“封箱”技术,"hello world"被强制转换 / 变换为 String 对象封装形式,而这是一个 iterable

ES6中还包括几个新的称为集合的数据结构。这些集合不仅本身是iterable,还提供了 API 方法来产生迭代器,比如:

var m = new Map();
m.set( "foo", 42 );
m.set( { cool: true }, "hello world" );
var it1 = m[Symbol.iterator]();
var it2 = m.entries();
it1.next(); // { value: [ "foo", 42 ], done: false }
it2.next(); // { value: [ "foo", 42 ], done: false }
..

4、可选的return(…)和throw(…)

return(…) 被定义为向迭代器发送一个信号,表明消费者代码已经完毕,不会再从其中提取任何值。这个信号可以用于通知生产者(响应 next(…) 调用的迭代器)执行可能需要的清理工作,比如释放 / 关闭网络、数据库或者文件句柄资源。

如果迭代器存在 return(…),并且出现了任何可以自动被解释为异常或者对迭代器消耗的提前终止的条件,就会自动调用 return(…)。你也可以手动调用 return(…)。

return(…) 就 像 next(…) 一样会返回一个IteratorResult 对 象。 一般来说,发送 return(…) 的可选值将会在这个 IteratorResult 中作为 value 返回,但在一些微妙的情况下并非如此。

throw(…) 用于向迭代器报告一个异常 / 错误,迭代器针对这个信号的反应可能不同于针对return(…) 意味着的完成信号。和对于 return(…) 的反应不一样,它并不一定意味着迭代器的完全停止。

例如,通过生成器迭代器,throw(…) 实际上向生成器的停滞执行上下文中插入了一个抛出的异常,这个异常可以用 try…catch 捕获。未捕获的 throw(…) 异常最终会异常终止生成器迭代器。

4、迭代器循环

如果一个迭代器也是一个 iterable,那么它可以直接用于 for…of 循环。你可以通过为迭代器提供一个 Symbol.iterator 方法简单返回这个迭代器本身使它成为 iterable:

var it = {// 使迭代器it成为iterable[Symbol.iterator]() { return this; },next() { .. },..
};
it[Symbol.iterator]() === it; // true

现在可以用 for…of 循环消耗这个 it 迭代器:

for (var v of it) {console.log( v );
}

要彻底理解这样的循环如何工作,可以看一下 for…of 循环的等价 for 形式:

for (var v, res; (res = it.next()) && !res.done; ) {v = res.value;console.log( v );
}

5、自定义迭代器

除了标准的内置迭代器,你也可以构造自己的迭代器!要使得它们能够与 ES6 的消费者工具(比如,for…of 循环以及… 运算符)互操作,所需要做的就是使其遵循适当的接口。让我们试着构造一个迭代器来产生一个无限斐波纳契序列:

var Fib = {[Symbol.iterator]() {var n1 = 1, n2 = 1;return {// 使迭代器成为iterable[Symbol.iterator]() { return this; },next() {var current = n2;n2 = n1;n1 = n1 + current;return { value: current, done: false };},return(v) {console.log("Fibonacci sequence abandoned.");return { value: v, done: true };}};}
};
for (var v of Fib) {console.log( v );if (v > 50) break;
}
// 1 1 2 3 5 8 13 21 34 55
// Fibonacci sequence abandoned.

调用 FibSymbol.iterator 方法的时候,会返回带有 next() 和 return(…) 方法的迭代器对象。通过放在闭包里的变量 n1 和 n2 维护状态。

6、迭代器消耗

前面已经展示了如何通过for…of循环一个接一个地消耗迭代器项目,但是还有其他ES6结构可以用来消耗迭代器。

var a = [1,2,3,4]
//spread运算符...完全消耗了迭代器。
function foo(x,y,z,w,p){console.log(x+y+z+w+p)
}
foo(...a)  //15
//...也可以把一个迭代器展开到一个数组中
var b = [0,...a,6]
b; //[0,1,2,3,4,5,6]

数组解构可以部分或完全消耗一个迭代器:

var it = a[Symbol.iterator]();
//从it中获取前两个元素
var [x,y] = it;
//获取第三个元素,然后一次取得其余所有元素
var [z,...w] = it
//it已将消耗完了吗?是的
it.next(); //{value:undefined,done:true}
x;//1
y;//2
z;//3
w;//[4,5]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/123629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode-哈希表

1. 理论 从哈希表的概念、哈希碰撞、哈希表的三种实现方式进行学习 哈希表:用来快速判断一个元素是否出现集合里。也就是查值就能快速判断,O(1)复杂度; 哈希碰撞:拉链法,线性探测法等。只是一种…

JAVA同城服务智慧养老小程序怎么开发?

随着人口老龄化的加剧,智慧养老成为了社会关注的焦点。智慧养老小程序作为一种便捷、高效的服务工具,为老年人提供了更全面、个性化的服务。本文将介绍如何使用JAVA编程语言开发一款同城服务智慧养老小程序。 一、设计思路 界面设计:小程序…

进程(详解)

进程 进程PCB进程的定义进程的组成进程模式进程的状态进程的运行进程的创建进程的结束孤儿进程僵尸进程僵尸进程的危害 进程的创建pidforkwait案例 进程 PCB 从操作系统理解进程概念-------先描述,后组织 为了使参与并发执行的程序能独立的运行,必须为之…

H5游戏源码分享-接苹果游戏拼手速

H5游戏源码分享-接苹果游戏拼手速 看看在20秒内能接多少个苹果 <html> <head><title>我是你的小苹果</title><meta charset"utf-8"/><meta name"viewport" content"initial-scale1, user-scalableno, minimum-scale…

浅谈数据治理(一)

治理工作如何对接下游推进 1.让下游配合最重要的是调动积极性&#xff0c;让下游感觉到治理能对他们起作用 或者说能让业务方也能做大蛋糕&#xff0c;因为数据治理对于下游来说可有可无 没你数据治理 下游数据模型不也跑的没问题嘛&#xff0c;所以就如花姐刚才说的该警告的警…

【ARM 嵌入式 C 入门及渐进 10 -- 冒泡排序 选择排序 插入排序 快速排序 归并排序 堆排序 比较介绍】

文章目录 排序算法小结排序算法C实现 排序算法小结 C语言中常用的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序。下面我们来一一介绍&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;冒泡排序是通过比较相邻元素的大小进行排…

LeetCode75——Day20

文章目录 一、题目二、题解 一、题目 2215. Find the Difference of Two Arrays Given two 0-indexed integer arrays nums1 and nums2, return a list answer of size 2 where: answer[0] is a list of all distinct integers in nums1 which are not present in nums2. an…

本机spark 通idea连接Oracle的坑

1. 报错&#xff1a;Exception in thread "main" java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V 查询网上资料&#xff0c;是idea引入的scala运行环境版本与idea默认的scala版本不一样 也就是写的项目中的pom的spark版本与idea默认的版本不…

【设计模式】第4节:创建型模式之“单例模式”

一、介绍 采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法。 不使用单例模式的UML类图&#xff1a; 使用单例模式的UML类图&#xff1a; 使用场景&#xff1a; 需要频繁创建或销毁的对象…

H5游戏分享-烟花效果

<!DOCTYPE html> <html dir"ltr" lang"zh-CN"> <head> <meta charset"UTF-8" /> <meta name"viewport" content"widthdevice-width" /> <title>点击夜空欣赏烟花</title> <sc…

Zabbix监控oxidized备份状态

Zabbix监控oxidized备份状态 原理是利用oxidized的hooks功能调用zabbix_sender推送数据给zabbix_server 参考 https://cloud.tencent.com/developer/article/1657025 https://github.com/clontarfx/zabbix-template-oxidized https://github.com/ytti/oxidized/blob/master/…

ES6模块化

ES6模块化是指在ES6标准中提供的一种JavaScript模块化方案&#xff0c;其本质是将不同的代码片段封装成独立的、可复用的模块&#xff0c;以便于管理和维护。使用ES6模块化可以使得代码更加清晰、易于维护、易于测试。 ES6模块化的特点包括&#xff1a; 每个模块都是独立的作用…

Python 日期和时间处理教程:datetime 模块的使用

Python 中的日期不是独立的数据类型&#xff0c;但我们可以导入一个名为 datetime 的模块来使用日期作为日期对象。 示例&#xff1a;导入 datetime 模块并显示当前日期&#xff1a; import datetimex datetime.datetime.now() print(x)日期输出 当我们执行上面示例中的代码…

如何确保PCIe Gen3通道的信号质量

PCIe 3.0设计面对的挑战 PCIe由PCI-SIG协会研发和维护的一个高速标准接口&#xff0c;PCIe3.0是其开发的第三代接口高速差分接口&#xff0c;其单个差分对信号速率可到达8.0Gbps&#xff0c;目前其以广泛的应用于计算机服务器等设备领域。 下图显示的是一个典型的PCIe Gen3的…

从JavaScript到Rust的三年时间小结

Rust 是一种注重安全性、速度和并发性的系统编程语言。它能编译成高效的本地代码&#xff0c;无需垃圾回收即可访问内存等底层资源&#xff0c;同时还能防止分隔故障。 作者讨论了他们几年来用 Rust 构建大型应用程序和库的经验。他们发现 Rust 的借用检查器和类型系统有助于减…

天气数据可视化平台-计算机毕业设计vue

天气变幻无常&#xff0c;影响着我们生活的方方面面&#xff0c;应用天气预报信息可以及时了解天气的趋势&#xff0c;给人们的工作、生活等带来便利&#xff0c;也可以为我们为未来的事情做安排和打算&#xff0c;所以一个精准的、易读 通过利用 程序对气象网站大量的气象信息…

ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

本文目录 前言Step 1 岸线数据Step 2 水深地形数据Step 3 其他数据及资料 前言 在利用MIKE建立水动力模型&#xff08;详见【MIKE水动力笔记】系列&#xff09;之前&#xff0c;需要收集、处理和制作诸多数据和资料&#xff0c;主要有岸线数据、水深地形数据、开边界潮位驱动数…

【C++】STL容器——探究不同 [ 迭代器 ] 种类&在STL中的使用方式(15)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 引言&#xff1a;一.查看STL使用文档时…

Java-API简析_java.io.FilterOutputStream类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/134106510 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

【蓝桥每日一题]-前缀和与差分(保姆级教程 篇3)#涂国旗 #重新排序

目录 题目&#xff1a;涂国旗 思路&#xff1a; 题目&#xff1a;重新排序 思路&#xff1a; 题目&#xff1a;涂国旗 思路&#xff1a; 乍一看好像没啥思路&#xff0c;但是我们需要涂最少的格子&#xff0c;所以要都尝试一下才行&#xff0c;也就是从上面开始白至少一行&am…