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

JavaScript高级 Iterator Generator

1. Iterator

1. JavaScript迭代器协议

在JavaScript中,迭代器也是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol):

◼ 迭代器协议定义了产生一系列值(无论是有限还是无限个)的标准方式;

◼ 在JavaScript中这个标准就是一个特定的next方法;

next方法有如下的要求:

◼ 一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象:

  1. done(boolean)

✓ 如果迭代器可以产生序列中的下一个值,则为 false。(这等价于没有指定 done 这个属性。)

✓ 如果迭代器已将序列迭代完毕,则为 true。这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值。

  1. value

✓ 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。

const names = ["abc", "cba", "nba"]// 给数组names创建一个迭代器(迭代器: names的迭代器)
let index = 0
const namesIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (index < names.length) {return { done: false, value: names[index++] }} else {return { done: true }}}
}console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())// 数组nums
const nums = [100, 24, 55, 66, 86]let indexNum = 0
const numsIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (indexNum < nums.length) {return { done: false, value: nums[indexNum++] }} else {return { done: true }}}
}

2. 维数组创建一个迭代器函数

为数组生成迭代器,封装函数优化

const names = ["abc", "cba", "nba"]
const nums = [100, 24, 55, 66, 86]// 封装一个函数
function createArrayIterator(arr) {let index = 0return {next: function() {if (index < arr.length) {return { done: false, value: arr[index++] }} else {return { done: true }}}}
}const namesIterator = createArrayIterator(names)
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())const numsIterator = createArrayIterator(nums)
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())

3. 创建可迭代对象

当一个对象实现了iterable protocol协议时,它就是一个可迭代对象;

这个对象的要求是必须实现 @@iterator 方法,在代码中我们使用 Symbol.iterator 访问该属性

// 将infos变成一个可迭代对象
/*1.必须实现一个特定的函数: [Symbol.iterator]2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
*/
const infos = {friends: ["kobe", "james", "curry"],[Symbol.iterator]: function() {let index = 0const infosIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (index < infos.friends.length) {return { done: false, value: infos.friends[index++] }} else {return { done: true }}}}return infosIterator}
}

4. 可迭代对象的操作

JavaScript中语法:for …of、展开语法(spread syntax)、yield*(后面讲)、解构赋值(Destructuring_assignment);

// 将infos变成一个可迭代对象
/*1.必须实现一个特定的函数: [Symbol.iterator]2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
*/
const infos = {friends: ["kobe", "james", "curry"],[Symbol.iterator]: function() {let index = 0const infosIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (index < infos.friends.length) {return { done: false, value: infos.friends[index++] }} else {return { done: true }}}}return infosIterator}
}for (const item of infos) {console.log(item)
}

创建一些对象时:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);

// 2.一些类的构造方法中, 也是传入的可迭代对象
const set = new Set(["aaa", "bbb", "ccc"])
const set2 = new Set("abc")
console.log(set2)
const set3 = new Set(info)
console.log(set3)

一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);

const p1 = Promise.resolve("aaaa")
const p2 = Promise.resolve("aaaa")
const p3 = Promise.resolve("aaaa")
const pSet = new Set()
pSet.add(p1)
pSet.add(p2)
pSet.add(p3)
Promise.all(pSet).then(res => {console.log("res:", res)
})

5. 原生迭代器

String、Array、Map、Set、arguments对象、NodeList集合都是可迭代对象,默认实现了[Symbol.iterator]函数

// 可迭代对象必然有一个[Symbol.iterator]函数
// 数组是一个可迭代对象
const students = ["张三", "李四", "王五"]
console.log(students[Symbol.iterator])
const studentIterator = students[Symbol.iterator]()
console.log(studentIterator.next())
console.log(studentIterator.next())
console.log(studentIterator.next())
console.log(studentIterator.next())

6. 自定义类的迭代

在面向对象开发中,我们可以通过class定义一个自己的类,这个类可以创建很多的对象,如果我们也希望自己的类创建出来的对象默认是可迭代的,那么在设计类的时候我们就可以添加上 @@iterator 方法;

class Person {constructor(name, age, height, friends) {this.name = namethis.age = agethis.height = heightthis.friends = friends}// 实例方法running() {}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.friends.length) {return { done: false, value: this.friends[index++] }} else {return { done: true }}}}return iterator}
}const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])
const p2 = new Person("kobe", 30, 1.98, ["curry", "james", "aonier", "weide"])for (const item of p2) {console.log(item)
}

7. 迭代器的中断

迭代器在某些情况下会在没有完全迭代的情况下中断:

  • 比如遍历的过程中通过break、return、throw中断了循环操作;

  • 比如在解构的时候,没有解构所有的值;

那么这个时候我们想要监听中断的话,可以添加return方法

class Person {constructor(name, age, height, friends) {this.name = namethis.age = agethis.height = heightthis.friends = friends}// 实例方法running() {}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.friends.length) {return { done: false, value: this.friends[index++] }} else {return { done: true }}},return: () => {console.log("监听到迭代器中断了")return { done: true }}}return iterator}
}const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])for (const item of p1) {console.log(item)if (item === "kobe") {break}
}

2. Generator

生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等

1. 生成器函数

生成器函数也是一个函数,但是和普通的函数有一些区别:

  • 首先,生成器函数需要在function的后面加一个符号:*

  • 其次,生成器函数可以通过yield关键字来控制函数的执行流程:

  • 最后,生成器函数的返回值是一个Generator(生成器):

✓ 生成器事实上是一种特殊的迭代器

/*生成器函数: 1.function后面会跟上符号: *2.代码的执行可以被yield控制3.生成器函数默认在执行时, 返回一个生成器对象* 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作* 当遇到yield时, 就会中断执行
*/// 1.定义了一个生成器函数
function* foo() {console.log("1111")console.log("2222")yieldconsole.log("3333")console.log("4444")yieldconsole.log("5555")console.log("6666")
}// 2.调用生成器函数, 返回一个 生成器对象
const generator = foo()
// 调用next方法
generator.next()
generator.next()
generator.next()

2. 生成器的参数和返回值

yield后面传入的参数是最后next后得到对象的value属性的值

// 1.定义了一个生成器函数
function* foo() {console.log("执行内部代码:1111")console.log("执行内部代码:2222")yield "aaaa"console.log("执行内部代码:3333")console.log("执行内部代码:4444")yield "bbbb"console.log("执行内部代码:5555")console.log("执行内部代码:6666")yield "cccc"
}// 2.调用生成器函数, 返回一个 生成器对象
const generator = foo("next1")
// 调用next方法
console.log(generator.next()) // { done: false, value: "aaaa" }
console.log(generator.next()) // { done: false, value: "bbbb" }
console.log(generator.next()) //  { done: false, value: "cccc" }
console.log(generator.next()) // {done: true, value: undefined}

中间return会使得next()之后返回对象的done变为true,value变为return的值

// 1.定义了一个生成器函数
function* foo() {console.log("执行内部代码:1111")console.log("执行内部代码:2222")yield "aaaa"console.log("执行内部代码:3333")console.log("执行内部代码:4444")return "bbbb"console.log("执行内部代码:5555")console.log("执行内部代码:6666")yield "cccc"
}// 2.调用生成器函数, 返回一个 生成器对象
const generator = foo("next1")
// 调用next方法
console.log(generator.next()) // { done: false, value: "aaaa" }
console.log(generator.next()) // { done: true, value: "bbbb" }
console.log(generator.next()) // { done: true, value: undefined }
console.log(generator.next()) // { done: true, value: undefined }
console.log(generator.next()) // { done: true, value: undefined }

generator.return()会直接结束迭代器

// 1.定义了一个生成器函数
function* foo() {console.log("执行内部代码:1111")console.log("执行内部代码:2222")yield "aaaa"console.log("执行内部代码:3333")console.log("执行内部代码:4444")yield "bbbb"console.log("执行内部代码:5555")console.log("执行内部代码:6666")yield "cccc"
}// 2.调用生成器函数, 返回一个 生成器对象
const generator = foo("next1")
// 调用next方法
console.log(generator.next()) // { done: false, value: "aaaa" }
console.log(generator.return()) // { done: true, value: undefined }
console.log(generator.next()) // { done: true, value: undefined }
console.log(generator.next()) // { done: true, value: undefined }
console.log(generator.next()) // { done: true, value: undefined }

执行的过程中传入参数

// 1.定义了一个生成器函数
function* foo(next1) {console.log("执行内部代码:1111", next1)console.log("执行内部代码:2222", next1)const next2 = yield "aaaa"console.log("执行内部代码:3333", next2)console.log("执行内部代码:4444", next2)return "bbbb"console.log("执行内部代码:5555")console.log("执行内部代码:6666")yield "cccc"
}// 2.调用生成器函数, 返回一个 生成器对象
const generator = foo("next1")
// 调用next方法
console.log(generator.next(next2))
console.log(generator.next(next3))

generator.throw()会直接抛出异常,但是需要捕获异常

3. 生成器替代迭代器

const names = ["abc", "cba", "nba"]
const nums = [100, 22, 66, 88, 55]function* createArrayIterator(arr) {for (let i = 0; i < arr.length; i++) {yield arr[i]}// yield arr[0]// yield arr[1]// yield arr[2]// return undefined
}

4. 生成器语法糖

这个时候相当于是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值

class Person {constructor(name, age, height, friends) {this.name = namethis.age = agethis.height = heightthis.friends = friends}// 实例方法*[Symbol.iterator]() {yield* this.friends}
}

相关文章:

JavaScript高级 Iterator Generator

1. Iterator 1. JavaScript迭代器协议 在JavaScript中&#xff0c;迭代器也是一个具体的对象&#xff0c;这个对象需要符合迭代器协议&#xff08;iterator protocol&#xff09;&#xff1a; ◼ 迭代器协议定义了产生一系列值&#xff08;无论是有限还是无限个&#xff09;…...

数字IC手撕代码--乐鑫科技(次小值与次小值出现的次数)

前言&#xff1a;本专栏旨在记录高频笔面试手撕代码题&#xff0c;以备数字前端秋招&#xff0c;本专栏所有文章提供原理分析、代码及波形&#xff0c;所有代码均经过本人验证。目录如下&#xff1a;1.数字IC手撕代码-分频器&#xff08;任意偶数分频&#xff09;2.数字IC手撕代…...

JavaScript DOM和BOM

目录 查找html元素 1.通过id 2.通过标签名 3.通过类名 DOM 1.创建动态的HTML内容 2.修改元素内容 3.改变HTML属性 4.改变css样式 DOM事件 DOM节点 1.添加HTML元素 2.删除HTML元素 浏览器对象 1.Window对象 2.Screen对象 3.History对象 4.Location对象 5.Navi…...

JUC并发编程(二)

一、过时方法 一些不推荐使用的方法已经过时&#xff0c;容易破坏同步代码块&#xff0c;使对象的锁得不到释放&#xff0c;进而造成线程死锁 二、守护线程 默认情况下&#xff0c;Java 进程需要等待所有线程都运行结束&#xff0c;才会结束。有一种特殊的线程叫做守护线程…...

Python控制CANoe使能TestCase

前面介绍了多种CANoe配置下的dbc文件添加,常见的配置我们能够常用的就是testcase的使能和环境变量的设置,针对于环境变量的问题,我们下次再进行详聊,今天主要聊一下测试脚本的使能。在做这块之前,我们第一步就需要了解我们的测试脚本的层级是都包含有哪些? 一、测试脚本结…...

sql的执行顺序

一.前言 在我们世家开发中,我们少不了和数据库打交道, 我们的持久层是与数据库打交道的, 少不了要用sql语句来请求数据库的数据, 前台(前端页面)请求到-->控制器(接口层)-->service(业务层)-->mapper或dao(持久层) 简图: 在持久层我们的sql是怎么执行的, 它的执行顺…...

java 8 中的实用技巧

1 判断2个对象是否相等Objects.equals(a, b)(1) 比较时&#xff0c; 若a 和 b 都是null, 则返回 true, 如果a 和 b 其中一个是null, 另一个不是null, 则返回false。注意&#xff1a;不会抛出空指针异常。(2) a 和 b 如果都是空值字符串&#xff1a;"", 则 a.equals(b…...

自学大数据的第一天

默认跳过基础部分,直接搞集群的部分,期间用到的linux基础默认大伙都会了(不会的话可以现用现查) Hadoop集群搭建 集群特点: 1,逻辑上分离~集群之间没有依赖,互不影响 2,某些进程往往部署在一台服务器上,但是属于不同的集群 3,MapReduce 是计算框架,代码层面的处理逻辑 集群的…...

redis秒杀

redis优惠券秒杀 为什么订单表订单ID不采用自增长&#xff1f; id规律性太明显&#xff0c;容易被用户猜测到&#xff08;比如第一天下订单id10&#xff0c;第二天下订单id100&#xff0c;在昨天的1天内只卖出90商品&#xff09;受单表数据量限制&#xff08;订单数据量大&am…...

JS学习第3天——Web APIs之DOM(什么是DOM,相关API【创建、增删改查、属性操作、事件操作API】)

目录一、Web APIs介绍1、API2、Web API二、DOM1、DOM树2、获取元素3、事件基础4、操作元素属性5、节点&#xff08;node&#xff09;操作三、DOM操作总结&#xff08;创建、增删改查、属性操作、事件操作API&#xff09;1、创建2、增3、删4、改5、查6、属性操作7、事件操作四、…...

【MySQL】增删改操作(基础篇)

目录 1、新增操作(Create) 1.1 单行数据 全列插入 1.2 多行数据 全列插入 1.3 单行数据 指定列插入 2、修改操作(Update) 3、删除操作(Delete) 1、新增操作(Create) 如何给一张表新增数据呢&#xff1f; 新增(Create)&#xff0c;在我们数据库中&#xff0c;用 ins…...

STM32—DMA

什么是DMA&#xff1f; DMA(Direct Memory Access&#xff0c;直接存储器访问) 提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通&#xff0c;而不需要依赖于CPU&#xff0c;在这个时间中&#xff0c;CPU对于内存的工作来…...

C语言刷题(3)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容还是做几道题噢&#xff0c;好好复习一下之前的知识点&#xff0c;现在&#xff0c;就让我们开始复习吧 牛客网在线编程_编程学习|练习题_数据结构|系统设计题库 倒置字符串_牛客题霸_牛客网 BC40 竞选社长 BC41 你是天才…...

搭建Vue工程

搭建Vue工程 localhost 127.0.0.1 域名 IP 192.168.0.28 联网IP 最后都会渲染到一个页面里面&#xff0c;有多少个页面就有多少个页面模板。 vue里面改webpack配置 vue.config.js 配置参考 | Vue CLI /assets /api* 开发的时候用到的请求后台地址 和 项目真实部署上线的时候 请…...

C语言汉诺塔问题【图文详解】

汉诺塔1. 什么是汉诺塔2. 有关汉诺塔的有趣故事3. 利用动画来演示汉诺塔4. 如何用C语言实现汉诺塔1. 什么是汉诺塔 源于印度古老传说的益智玩具 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造…...

1、RocketMQ概述

文章目录1 MQ概述1.1 MQ简介1.2 MQ用途1.3 常见MQ产品1.4 MQ常见协议2 RocketMQ概述2.1 RocketMQ简介2.2 RocketMQ发展历程尚硅谷RocketMQ教程-讲师&#xff1a;Reythor雷&#xff08;老雷&#xff09; 我们缺乏的不是知识&#xff0c;而是学而不厌的态度 1 MQ概述 1.1 MQ简介…...

【POJ 3352】Road Construction 题解(Tarjan算法求边双连通分量缩点)

描述 现在几乎是夏天&#xff0c;这意味着几乎是夏天的施工时间&#xff01;今年&#xff0c;负责偏远岛热带岛屿天堂道路的好心人希望修复和升级岛上各个旅游景点之间的各种道路。 道路本身也很有趣。由于岛上的奇怪风俗&#xff0c;道路的安排使得它们不会在交叉路口相遇&…...

Python—单分支结构

&#xff08;1&#xff09;if分支语句 Python中if语句的语法结构&#xff1a; if <条件表达式>&#xff1a;    满足条件运行的代码1    满足条件运行的代码2 代码示例&#xff1a; age 12 if age > 18:print(去上网)if 1 1 2 and :print(我满足条件了)if 1 …...

rabbitmq添加用户,虚拟机步,设置rabbitmq配置文件

第一步&#xff0c;登录后台控制页面 http://ip:15672第二步&#xff0c;添加用户和权限 重点&#xff1a;选择Admin和Users 第三步&#xff0c;添加虚拟机 点击侧边的Virtual Hosts 第四步将虚拟机和用户搭配 注意新建好后&#xff0c;在虚拟机列表中&#xff0c;点击虚拟机…...

Codeforces Round#853 div2 A-C

Codeforces Round#853 div2 A-C 等了很久终于迎来了一场cf比赛&#xff0c;白天出去玩了一圈&#xff0c;晚上回来打比赛&#xff0c;这次只出了A,B题。C题思路很巧妙&#xff0c;赛时没做出来&#xff0c;看了大佬学习到了&#xff0c;还是很不错。 A.Serval and Mocha’s A…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...