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

ES6中迭代器与生成器知识浅析

ES5及以下版本对JS几种集合,要存取数据一般需要用循环语句来遍历,就要初始化一个或多个变量来记录每一次循环在数据集合中的位置或数据值。这里容易出现超出边界问题,造成程序出错。另外,对于多次循环也需要跟踪理清各个变量关系及存续问题,造成问题复杂化和不安全性。

ES6开始引入迭代器,它可以极大的简化数据操作,不需要额外的临时变量,本身带有内部查找及循环机制。对于程序员来说,只需要取用即可,取用一次,集合内部迭代器自动更新,并将指针指向下一个数据,完全不用操心遍历循环设计及控制问题。

在ES6中,Map集合等众多集合,JS本身就具有内建迭代器功能,可以直接使用其内联迭代器。而对于其他不具有迭代功能的集合或用户自己生成的集合,是不具有迭代器功能的。因此,生成器就是让用户在建立集合时就加入迭代功能,生成相关迭代语句,以便后面使用它时可以运用迭代功能。

 一、什么是迭代器

迭代器是一种特殊对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值(对应调用next次数序号数据值),如果是最后一个或更后的调用next()方法,则value返回undefined;另一个是done,它是一个布尔类型的值,当没有可返回数据时返回true,有返回数据时为false。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可能的值。

下面,用ES5模拟生成器与迭代器使用过程(极简化版模拟):

function createIterator(items){//模拟生成器内部实现过程

       var i=0;

       return{

              next:function(){

                     var done=(i>=items.length);

                     var value=!done?items[i++]:undefined;

                     return{

                            done:done,

                            value:value

                     };

              }

       };

}

var iterator=createIterator([1,2,3]);//定义迭代器

console.log(iterator.next());//输出结果:{value:1,done:false}

console.log(iterator.next());//输出结果:{value:2,done:false}

console.log(iterator.next());//输出结果:{value:3,done:false}

console.log(iterator.next());//输出结果:{value:undefined,done:true},之后所有调用next()方法都会是这个结果

二、什么是生成器

生成器是一种返回迭代器的函数,通过function关键字后的星号“*”来表示,函数中会用到新的关键字yield。星号紧挨着function关键字,也可以在中间添加一个空格。

//生成器

function *createIterator(){//*表示该函数是一个迭代器生成器

       yield 10;//yield关键字定义迭代器next()方法调用的返回值和顺序

       yield 20;

       yield 30;

}

//生成器的调用方式与普通函数相同,只不过返回的是一个迭代器

let iterator=createIterator();

console.log(iterator.next().value);//输出结果:10

console.log(iterator.next().value);//输出结果:20

console.log(iterator.next().value);//输出结果:30

console.log(iterator.next().value);//输出结果:undefined

三、生成器的使用方法要点

1.生成器yield并不是直接生成可迭代的集合对象

它只是生成一个迭代器,就象给一个运行员打了一针兴奋器,可以让该运动员比没打前跑得更快,而一个“yield  10;”语句,则是表示对于10这个数据可以用next()方法来加速查找(不需要循环结果及变量辅助)。

而要生成一个可迭代的集合对象,则是需要在生成集合对象的过程中,每一个数据生成时都要调用生成器函数,用yield去定义数据,这样最终形成的集合对象才是迭代集合对象。就如上面的生成器示例中,如果20和30不用yield去定义,则不能再第二次和第三次next()方法中取到这个两值,因为没有给它们生成可以用next方法迭代的过程。

2.使用yield关键字可以返回任何值或表达式

所以可以通过生成器函数批量地给迭代器添加元素。如下示例:

function *createIterator(items){

              for(let i=0;i<items.length;i++){

                yield items[i];

        }

}

let iterator=createIterator(["张小玉","孙大壮","李强"]);

console.log(iterator.next());//输出结果:{value:张小玉,done:false}

console.log(iterator.next());//输出结果:{value:孙大壮,done:false}

console.log(iterator.next());//输出结果:{value:李强,done:false}

console.log(iterator.next());//输出结果:{value:undefined,done:true}

3.yield关键字只可在生成器内部使用,在其他地方使用会报错

即使用在生成器内部的函数里使用也不行。也就是说,生成器函数中除了yield开头的语句,只能出现块状体{}中,如if{}、for(){}等作为yield生成有关的逻辑体外,其他无关的定义变量、赋值等语句,如果不是以yield开头,都将报错。

下面为错误的使用yield示例:

function *createIterator(items){//错误的使用yield

              items.forEach(function(item){

                     //语法错误,因为参数为函数,不属于块状作用域

                     yield item+1;//报错,Unexpected identifier 'item'

              });

}

let iterator=createIterator([1,2,3]);

console.log(iterator.next());//输出结果:无输出

console.log(iterator.next());//输出结果:无输出

console.log(iterator.next());//输出结果:无输出

console.log(iterator.next());//输出结果:无输出

下面为正确的使用yield示例:

function *createIterator(items){//正确的使用yield

        for(let item of items){

               yield item+1;

        };

}

let iterator=createIterator([1,2,3]);

console.log(iterator.next().value);//输出结果:2

console.log(iterator.next().value);//输出结果:3

console.log(iterator.next().value);//输出结果:4

console.log(iterator.next().value);//输出结果:undefined

4.生成器对象的方法

let o={

       createIterator:function *(items){

              for(let i=0;i<items.length;i++){

                     yield items[i];

              }

       }

};

let iterator=o.createIterator([1,2,3]);

console.log(iterator.next().value);//输出结果:1

console.log(iterator.next().value);//输出结果:2

console.log(iterator.next().value);//输出结果:3

console.log(iterator.next().value);//输出结果:undefined

四、具有内联迭代器的集合

在ES6中,已经默认为许多类型(主要有数组、Map集合和Set集合)建立了内联迭代器,只有当这些内联迭代器无法实现你的目标时才需要自己创建,并用生成器加入迭代器。

(一)通过Symbol.iterator来访问内联集合的默认迭代器

1.访问默认迭代器

et values=[1,2,3];//定义数组

let iterator=values[Symbol.iterator]();//获得数组的默认迭代器

console.log(iterator.next());//输出结果:{value:1,done:false}

console.log(iterator.next());//输出结果:{value:2,done:false}

console.log(iterator.next());//输出结果:{value:3,done:false}

console.log(iterator.next());//输出结果:{value:undefined,done:true}

2.创建可迭代对象

默认情况下,开发者定义的对象都是不可迭代的对象,但如果给Symbol.iterator属性添加一个生成器,则其也具有了默认迭代器。

let collection={//创建可迭代对象

       items:[],

       *[Symbol.iterator](){

              for(let item of thi.items){

                     yield item;

              }

       }

};

collection.items.push(10);//给对象赋值

collection.items.push(20);

collection.items.push(30);

let iterator=collection.items[Symbol.iterator]();//建立默认迭代器

console.log(iterator.next());//输出结果:{value:10,done:false}

console.log(iterator.next());//输出结果:{value:20,done:false}

console.log(iterator.next());//输出结果:{value:30,done:false}

console.log(iterator.next());//输出结果:{value:undefined,done:true}

(二)访问内联迭代器

内联集合有三个内联迭代器:

第一个:entries(),返回一个迭代器,其值为多个键值对

第二个:values(),返回一个迭代器,其值为集合的值

第三个:keys(),返回一个迭代器,其值为集合中的所有键名

1. entries()迭代器

每次调用next()方法时,都会返回一个数组,数组中的两个元素分别表示键与值。如果是数组,第一个是索引,每二个是值;如果是Set集合,两个都是值;如果是Map集合,第一个为键名,第二个为值。

let colors=["red","green","blue"]//数组集合

for(let entry of colors.entries()){

       console.log(entry);//输出结果:{[0,"red"],[1,"green"],[2,"blue"]}

}

let tracking=new Set([10,20,30]);//Set集合

for(let netry of tracking.entries()){

       console.log(netry);//输出结果:{[10,10],[20,20],[30,30]}

}

let data=new Map();//Map集合

data.set("第一名","张小玉");

data.set("第二名","孙大壮");

data.set("第三名","李强");

for(let entry of data.entries()){

       console.log(entry);//输出结果:{["第一名","张小玉"],["第二名","孙大壮"],["第三名","李强"]}

}

2. values()迭代器

调用values()迭代器时会返回集合中所存的所有值,如:

let colors=["red","green","blue"]//数组集合

for(let entry of colors.values()){

       console.log(entry);//输出结果:{"red","green","blue"}

}

let tracking=new Set([10,20,30]);//Set集合

for(let netry of tracking.values()){

       console.log(netry);//输出结果:{10,20,30}

}

let data=new Map();//Map集合

data.set("第一名","张小玉");

data.set("第二名","孙大壮");

data.set("第三名","李强");

for(let entry of data.values()){

       console.log(entry);//输出结果:{"张小玉","孙大壮","李强"}

}

3. keys()迭代器

调用keys()迭代器会返回集合中存在的键。

let colors=["red","green","blue"]//数组集合

for(let entry of colors.keys()){

       console.log(entry);//输出结果:{0,1,2}

}

let tracking=new Set([10,20,30]);//Set集合

for(let netry of tracking.keys()){

       console.log(netry);//输出结果:{10,20,30}

}

let data=new Map();//Map集合

data.set("第一名","张小玉");

data.set("第二名","孙大壮");

data.set("第三名","李强");

for(let entry of data.keys()){

       console.log(entry);//输出结果:{"第一名","第二名","第三名"}

}

相关文章:

ES6中迭代器与生成器知识浅析

ES5及以下版本对JS几种集合&#xff0c;要存取数据一般需要用循环语句来遍历&#xff0c;就要初始化一个或多个变量来记录每一次循环在数据集合中的位置或数据值。这里容易出现超出边界问题&#xff0c;造成程序出错。另外&#xff0c;对于多次循环也需要跟踪理清各个变量关系及…...

unix中的vfork函数

一、前言 本文介绍unix中的vfork函数&#xff0c;vfork函数功能和fork函数类似&#xff0c;也是用于创建新的进程&#xff0c;只不过调用vfork函数创建的子进程将共享父进程的进程空间&#xff0c;且只有当子进程调用exec()或者exit()函数后&#xff0c;父进程才会继续运行。 …...

Android 用线程池实现一个简单的任务队列(Kotlin)

关于线程池,Kotlin和java的使用方式一样 在Android中,很多人喜欢用Handler的postDelayed() 去实现延时任务. 要使用postDelayed(),去实现延时任务队列,就不可避免要使用递归. 但是这样做,代码的简洁性,和书写的简易,就远不如使用线程池. 使用线程池的简单程度: private val…...

遨游信息技术的浩瀚宇宙:探索MySQL的深邃奥秘

遨游信息技术的浩瀚宇宙&#xff1a;探索MySQL的深邃奥秘 在信息技术的浩瀚宇宙中&#xff0c;MySQL犹如一颗璀璨的星辰&#xff0c;以其稳定、高效、灵活的特性&#xff0c;照亮了无数开发者与数据管理者的前行之路。作为关系型数据库管理系统的佼佼者&#xff0c;MySQL不仅承…...

【Bug解决】Nacos启动成功,但却无法访问(提示:无法访问此网站,192.168.10.88的响应时间过长)

项目场景&#xff1a; 在虚拟机上通过Docker创建Nacos容器&#xff0c;已经创建成功&#xff0c;查看Nacos启动日志也是成功。但通过端口号加8848/nacos&#xff08;如&#xff1a;http://IP:8848/nacos&#xff09;无法访问到Nacos管理页面。 愿意分析一&#xff1a; 先检查好…...

【AI创作组】工程方向的硕士研究生学习Matlab的路径

1. MATLAB软件概述 1.1 MATLAB发展历程 MATLAB自20世纪70年代诞生以来,已经经历了多次重要的版本更新和功能扩展。 初始版本:MATLAB的前身只是一个简单的交互式矩阵计算器,由Cleve B. Moler博士在1970年代初期开发,目的是为了方便学生和研究人员使用线性代数软件包LINPAC…...

Mac使用Nginx设置代理,并禁用自带Apache

Mac自带Apache服务&#xff0c;并占用80端口&#xff0c;如果需要使用Nginx&#xff0c;需要禁用Apache并自己安装Nginx 一、禁用自带Apache 1.关闭Apache sudo apachectl -k stop 如果出现如下报错&#xff1a;httpd: Could not reliably determine the server’s fully q…...

AlmaLinux 安裝JDK8

在 AlmaLinux 上安装 JDK 8 可以通过包管理器 dnf 来完成。AlmaLinux 是基于 RHEL 的一个开源发行版&#xff0c;因此其包管理系统和 RHEL 类似。以下是详细的步骤来安装 OpenJDK 8 1. 更新系统包列表 sudo dnf update -y 2. 安装 OpenJDK 8 使用 dnf 安装 OpenJDK 8。你可…...

Set 和 Map 的模拟实现

1、引言 在数据结构与算法的学习与实践中&#xff0c;关联容器&#xff08;associative containers&#xff09;是不可忽视的重要工具。作为高效管理数据的一类容器&#xff0c;C 标准库中的 set 和 map 在现代软件开发中扮演着关键角色。这两个容器通过平衡二叉搜索树&#x…...

深度学习自编码器 - 预测稀疏分解(PSD)篇

序言 在数据科学与机器学习的广阔领域中&#xff0c;深度学习作为一股不可忽视的力量&#xff0c;正引领着技术革新的浪潮。其中&#xff0c;自编码器&#xff08; Autoencoder \text{Autoencoder} Autoencoder&#xff09;作为一种特殊的神经网络结构&#xff0c;以其独特的自…...

如何检测出来这个ip是共享ip不安全

检测一个IP是否为共享IP以及其安全性可以通过以下几种方法和工具来进行分析。共享IP通常是指多个用户共享一个IP地址&#xff0c;常见于公共代理服务器、VPN服务或数据中心IP。如果你想评估一个IP是否为共享IP以及其安全性&#xff0c;以下方法和工具可以帮助你进行检测和分析。…...

TMStarget学习——T1 Segmentation数据处理及解bug

最新学习季公俊老师的神器 TMStarget 的第一个模块基于结构像的靶区计算T1 segmentation。下面上步骤&#xff1a; (1)在github 上下载 TMStarget https://github.com/jigongjun/Neuroimaging-and-Neuromodulation (2)按照要求下载依赖工具软件AFQ、vistasoft、SPM12 &#…...

锁策略, cas 和 synchronized 优化过程

1.1 常見的鎖策略 預測鎖衝突概率 樂觀鎖&#xff1a;加鎖的時候&#xff0c;假設出現鎖衝突的概率不大。圍繞加鎖做的工作會更少。 悲觀鎖&#xff1a;加鎖的時候&#xff0c;假設鎖出現衝突的概率很大。圍繞加鎖做的工作會更多。 synchronized “自適應” 初始是樂觀的。鎖…...

【HTML5】html5开篇基础(2)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…...

大数据新视界 --大数据大厂之 Reactjs 在大数据应用开发中的优势与实践

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

【论文阅读笔记】TOOD: Task-aligned One-stage Object Detection

论文代码&#xff1a;https://github.com/fcjian/TOOD 文章目录 论文小结论文简介论文方法Task-aligned Head&#xff08;T-Head&#xff09;T-Head伪代码解释 Task Alignment Learning&#xff08;TAL&#xff09;Task-aligned Sample AssignmentTask-aligned Loss 论文实验消…...

类中的特殊内容

仿照string类&#xff0c;自己手动实现 My_string #include <iostream> #include <string.h> using namespace std;class My_string { private:int len;int size;char *ptr; public:My_string():size(15),len(0){ptrnew char[size];ptr[0]\0;}My_string(const char…...

network request to https://registry.npmjs.org/xxx failed, reason: connect ETIM

目录&#xff1a; 1、问题描述2、解决方案3、npm镜像仓库替换 1、问题描述 npm install 时&#xff0c;报错&#xff1a;npm ERR! network request to https://registry.npmjs.org/postcss-pxtorem failed, reason: connect ETIMEDOU npm ERR! code ETIMEDOUT npm ERR! errno…...

MQ入门(二):java客户端SpringAMQP

目录 1.SpringAMQP 1.1.导入demo工程 1.2.快速入门 1.2.1.消息发送 1.2.2.消息接收 1.2.3.测试 1.3.WorkQueues模型 1.4.交换机类型 1.4.1.Fanout交换机 1.4.2.Direct交换机 1.4.3.Topic交换机 1.5.声明队列和交换机 1.5.1.基于注解声明 1.6.消息转换器 1.6.1.测…...

软技能与AI技术的融合

一、引言 ----  随着人工智能&#xff08;AI&#xff09;和生成式人工智能&#xff08;AIGC&#xff09;如ChatGPT、Midjourney、Claude等大语言模型的迅速崛起&#xff0c;AI辅助编程工具已经变得越来越普遍。这不仅意味着程序员的工作方式正在发生深刻的变革&#xff0c;同…...

在视频上绘制区域:使用Vue和JavaScript实现交互式画布

在数字时代&#xff0c;交互式媒体内容的创建和消费变得越来越普遍。特别是视频内容&#xff0c;它不仅提供了视觉信息&#xff0c;还允许用户与之互动&#xff0c;从而增强了用户体验。本文将介绍如何使用Vue.js框架和JavaScript创建一个交互式组件&#xff0c;该组件允许用户…...

31. RabbitMQ顺序消费

1. 前言 上个小节中我们介绍了 RabbitMQ 中如何防止消息丢失,即保证消息发送的 At Least Once 性质,除此之外,如何防止消息被重复消费,即保证消息消费的 Exactly Once 性质,也是业务逻辑中需要考虑的问题。 2. 消息消费顺序 面试官提问:业务中使用了 RabbitMQ 消息队列…...

BERT-BiLSTM-CRF模型实战

文章目录 BERT-BiLSTM-CRF模型项目结构数据预处理运行环境使用方法关于BERT-BiLSTM-CRF参考文章BERT-BiLSTM-CRF模型 使用谷歌的BERT模型在BiLSTM-CRF模型上进行预训练用于中文命名实体识别。 项目结构 bert_bilstm_crf_ner_pytorchtorch_nerbert-base-chinese --…...

npm 安装 与 切换 淘宝镜像

一、镜像源 npm默认镜像源是国外的&#xff0c;安装依赖速度较慢&#xff0c;使用国内的镜像源速度会快一些。 1、设置淘宝镜像源&#xff1a; #最新地址 淘宝 NPM 镜像站喊你切换新域名啦! npm config set registry https://registry.npm.taobao.org&#xff08;弃用了&…...

在Windows系统上安装的 Arrow C++ 库

在Windows系统上安装的 Arrow C 库 正文第一步第二步第三步第四步注: 检查是否安装成功 吐槽 正文 第一步 git clone gitgithub.com:apache/arrow.git第二步 打开powershell (好像cmd也可以,不过我试了powershell中不报错,cmd中报错,不是很清楚为什么) 打开arrow的目录 cd …...

格雷母线电缆头安装方法视频-武汉正向科技

正向科技|格雷母线电缆头怎么处理&#xff1f; 正向科技格雷母线采用整体热压工艺生产&#xff0c;一次成型&#xff0c;防护等级 IP67&#xff0c;用在直线或环形位移检测&#xff0c;抗污染能力强&#xff0c;防水、油、灰尘、蒸汽等&#xff0c;能在强粉尘、高温的环境下稳定…...

统信服务器操作系统【Cron定时任务服务】

Cron定时任务服务服务介绍、服务管理、服务配置 文章目录 一、功能概述二、功能介绍1. Cron 服务管理2.Cron 服务管理3.Cron 服务配置run-parts一、功能概述 cron是一个可以用来根据时间、日期、月份、星期的组合来 调度对周期性任务执行的守护进程。利用 cron 所提供的功能,可…...

微前端中的路由加载流程

1. 初始化基座应用 基座应用&#xff1a;基座应用是微前端架构中的主应用&#xff0c;负责管理和协调各个子应用的加载和卸载。 初始化&#xff1a;基座应用在启动时会初始化路由配置&#xff0c;注册各个子应用的路由。 2. 注册子应用 子应用需要向基座应用注册自己的路由和…...

Axure大屏可视化模板:跨领域数据分析平台原型案例

随着信息技术的飞速发展&#xff0c;数据可视化已成为各行各业提升管理效率、优化决策过程的重要手段。Axure作为一款强大的原型设计工具&#xff0c;其大屏可视化模板在农业、园区、城市、企业数据可视化、医疗等多个领域得到了广泛应用。本文将通过几个具体案例&#xff0c;展…...

机器学习(1)——线性回归、线性分类与梯度下降

文章目录 线性回归线性分类线性可分数据线性不可分数据逻辑回归支持向量机 梯度下降批量梯度下降随机梯度下降批量随机梯度下降 线性回归 概述&#xff1a; 在一元线性回归中&#xff0c;我们假设目标变量y与特征变量x存在线性关系&#xff0c;模型表达式为&#xff1a; y …...