JS生成器的介绍

news2024/11/19 15:37:13

1、 什么是生成器

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

平时我们会编写很多的函数,这些函数终止的条件通常是返回值或者发生了异常。
生成器函数也是一个函数,但是和普通的函数有一些区别:

首先,生成器函数需要在function的后面加一个符号:*
其次,生成器函数可以通过yield关键字来控制函数的执行流程
最后,生成器函数的返回值是一个Generator(生成器)
生成器事实上是一种特殊的迭代器

2、 生成器的声明

生成器是一个函数的形式,通过在函数名称前加一个星号(*)就表示它是一个生成器。所以只要是可以定义函数的地方,就可以定义生成器

function* gFn() { }

const gFn = function* () { }

const o = {
    * gFn() { }
}

箭头函数不能用来定义生成器函数,因为生成器函数使用( function*)语法编写。
那为啥上面的第三个例子可以不使用 (function*)语法呢?
因为那个是简写版本。等价于:

const o = {
    gFn: function* () { }
}

3、 生成器的使用

3.1 生成器函数执行

function* gFn() {
    console.log(111)
}
gFn()

然后,我们会很"开心"地发现控制台没有打印任何信息。
这是因为调用生成器函数会产生一个生成器对象,但是这个生成器一开始处于暂停执行的状态,需要调用 next方法才能让生成器开始或恢复执行。

return会直接让生成器到达 done: true状态:

function* gFn() {
    console.log(111)
    return 222
}
const g = gFn()
console.log("1",g)
console.log("2",g.next())
console.log("3",g.next())

在这里插入图片描述
生成器代码的执行可以被yield控制:

function* gFn() {
     yield 
     console.log(111)
     return 222
}
const g = gFn()
console.log("1",g)
console.log("2",g.next())
console.log("3",g.next())

yield关键字
提到生成器,自然不能忘记 yield关键字。 yield能让生成器停止,此时函数作用域的状态会被保留,只能通过在生成器对象上调用 next方法来恢复执行。
上面我们已经说了, return会直接让生成器到达 done: true状态,而 yield则是让生成器到达 done: false状态,并停止

在这里插入图片描述

我们很多时候不希望next返回的是一个undefined,这个时候我们可以通过yield来返回结果:

function* gFn() {
     yield 100
     console.log(111)
     return 222
}
const g = gFn()
console.log("1",g)
console.log("2",g.next())
console.log("3",g.next())

在这里插入图片描述
3.2 生成器传递参数
函数既然可以暂停来分段执行,那么函数应该是可以传递参数的,我们是否可以给每个分段来传递参数呢?
答案是可以的, 我们在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值;

function* gFn(initial) {
  console.log(initial)
  console.log(yield)
  console.log(yield)
  console.log(yield)
}
const g = gFn('red')
g.next('white')
g.next('blue')
g.next('purple')

在这里插入图片描述

  1. 生成生成器,此时处于暂停执行的状态
  2. 调用 next,让生成器开始执行,输出 red,然后准备输出 yield,发现是 yield,暂停执行,出去外面一下。
  3. 外面给 next方法传参 blue,又恢复执行,然后之前暂停的地方(即 yield)就会接收到 blue。然后又遇到 yield暂停。
  4. 又恢复执行,输出 purple

然后,可能就会有人问,第一次传的 white怎么消失了?
它确实消失了,因为第一次调用 next方法是为了开始执行生成器函数,而刚开始执行生成器函数时并没有 yield接收参数,所以第一次调用 next的值并不会被使用。

yield关键字同时用于输入和输出: yield可以和 return同时使用,同时用于输入和输出

function* gFn() {
  yield 111
  return yield 222
}
const g = gFn()
console.log(g.next(333))
console.log(g.next(444))
console.log(g.next(555))

在这里插入图片描述

  1. 生成生成器,此时处于暂停执行的状态
  2. 调用 next,让生成器开始执行,遇到 yield,暂停执行,因为 yield后面还有111,所以带着111作为输出出去外面。
  3. 调用 next,生成器恢复执行,遇到 return,准备带着后面的数据跑路,结果发现后面是
    yield,所以又带着222,作为输出到外面。
  4. 调用 next,又又又恢复执行,不过这个时候return的内容是 yield表达式,所以 yield会作为输入接收555,然后再把它带到外面去输出。

yield表达式需要计算要产生的值,如果后面没有值,那就默认是 undefined。 return yield x的语法就是,遇到 yield,先计算出要产生的值 111,在暂停执行的时候作为输出带出去,然后调用 next方法时, yield又作为输入接收 next方法的第一个参数

3.3 生成器抛出异常
throw也可以提前终止生成器,且会抛出异常,需要捕获处理抛出的异常。

function* gFn() {
  yield 111
  yield 222
  yield 333
}

const g = gFn()
// g.throw(444)       // 如果异常没有被处理的话,会直接报错

try {
  g.throw(444)
} catch (e) {
  console.log(e)
}
console.log(g)
console.log(g.next())

在这里插入图片描述
不过,如果处理异常是在生成器内部的话,情况就不太一样了。

function* gFn() {
  for (const x of [1, 2, 3]) {
    try {
      yield x
    } catch (e) {
      console.log(e)
    }
  }
}
const g = gFn()
console.log(g.next())
g.throw(444)
console.log(g)
console.log(g.next())

如果是在生成器内部处理这个错误,那么生成器不会关闭,还可以恢复执行,只是会跳过对应的yield,即会跳过一个值。

4、 生成器替代迭代器

我们发现生成器是一种特殊的迭代器,那么在某些情况下我们可以使用生成器来替代迭代器:

const names = ["aaa", "bbb", "ccc"]

function* gFn(arr) {
  for (let i = 0; i < arr.length; i++) {
    yield arr[i]
  }
}

const g = gFn(names )
console.log(g.next()) 
console.log(g.next())
console.log(g.next())
console.log(g.next())

在这里插入图片描述
事实上我们还可以使用yield*来生产一个可迭代对象:这个时候相当于是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值;

const names = ["aaa", "bbb", "ccc"]

function* gFn(arr) {
    yield* arr
}

const g = gFn(names)
console.log(g.next()) 
console.log(g.next())
console.log(g.next()) 
console.log(g.next()) 

结果同上!

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

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

相关文章

阿里云无影云电脑是干什么用的?五大使用场景

阿里云无影云电脑是一种易用、安全、高效的云上桌面服务&#xff0c;阿里云无影云电脑可用于高数据安全管控、高性能计算等要求的金融、设计、视频、教育等领域&#xff0c;适用于多种办公场景&#xff0c;如远程办公、多分支机构、安全OA、短期使用、专业制图等。阿里云百科来…

【LeetCode热题100】--49.字母异位词分组

49.字母异位词分组 两个字符串互为字母异位词&#xff0c;当且仅当两个字符串包含的字母相同。同一组字母异位词中的字符串具备相同点&#xff0c;可以使用相同点作为一组字母异位词的标志&#xff0c;使用哈希表存储每一组字母异位词&#xff0c;哈希表的键为一组字母异位词的…

DockerCompose

DockerCompose Docker Compose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器&#xff01; 初识DockerCompose Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。格式如下&#xff1a; version: &…

[golang 流媒体在线直播系统] 4.真实RTMP推流摄像头把摄像头拍摄的信息发送到腾讯云流媒体服务器实现直播

用RTMP推流摄像头把摄像头拍摄的信息发送到腾讯云流媒体服务器实现直播,该功能适用范围广,比如:幼儿园直播、农场视频直播, 一.准备工作 要实现上面的功能,需要准备如下设备: 推流摄像机&#xff08;监控&#xff09; 流媒体直播服务器(腾讯云流媒体服务器,自己搭建的流媒体服务…

React中组件通信01——props

React中组件通信01——props 1. 父传子——props1.1 简单例子——props1.2 props 可以传递任何数据1.2.1 传递数字、对象等1.2.2 传递函数1.2.3 传递模版jsx 2. 子传父 子传子——props2.1 父传子——传递函数2.2 子传父——通过父传子的函数实现2.3 优化 子传子&#xff08;…

uniapp开发小程序中实现骨架屏

第一步&#xff1a;小程序中实现骨架屏在微信开发者工具中点击生成骨架屏&#xff1a; 第二步&#xff1a;复制html代码&#xff0c;到骨架屏vue组件汇中再把之前写的样式代码引入进去&#xff1a; import ../../pages/user/user.css; 第三步&#xff1a;组件中引入骨架屏&am…

python pytesseract 中文文字批量识别

用pytesseract 来批量把图片转成文字 1、安装好 pytesseract 包 2、下载安装OCR https://download.csdn.net/download/m0_37622302/88348824https://download.csdn.net/download/m0_37622302/88348824 Index of /tesseracthttps://digi.bib.uni-mannheim.de/tesseract/ 我是…

百度SEO优化TDK介绍(分析下降原因并总结百度优化SEO策略)

TDK是SEO优化中很重要的部分&#xff0c;包括标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keyword&#xff09;&#xff0c;为百度提供网页内容信息。其中标题是最重要的&#xff0c;应尽量突出关键词&#xff0c;同时描述…

【C++学习】继承

目录 一、继承的概念及定义 1、继承的概念 2、继承的定义 2.1 定义格式 2.2 继承关系和访问限定符 2.3 继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员 七、复杂的菱形…

天然气跟踪监管系统功能模块实现

天然气跟踪监管系统功能模块实现 1. 数据库查询3. 仓库管理&#xff08;1&#xff09;仓库查询与展示。代码说明 1. 数据库查询 救援物资跟踪监管系统的绝大部分功能都会涉及关系数据库中的业务数据&#xff0c;因此关系数据库的查询是本系统不可或缺的重要部分。 本系统中的数…

Matlab--微积分问题的计算机求解

目录 1.单变量函数的极限问题 1.1.公式例子 1.2.对应例题 1 2.多变量函数的极限问题 3.函数导数的解析解 4.多元函数的偏导数 5.Jacobian函数 6.Hessian矩阵 7.隐函数的偏导 8.不定积分问题的求解 9.定积分的求解问题 10. 多重积分的问题求解 1.单变量函数的极限问题 …

【Vue】快速入门案例与工作流程的讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Vue快速入门》。&#x1f…

运维Shell牛刀小试(十一):for循环读取多个命令行参数|read重定向读取文件内容

运维Shell脚本小试牛刀(一) 运维Shell脚本小试牛刀(二) 运维Shell脚本小试牛刀(三)::$(cd $(dirname $0)&#xff1b; pwd)命令详解 运维Shell脚本小试牛刀(四): 多层嵌套if...elif...elif....else fi_蜗牛杨哥的博客-CSDN博客 Cenos7安装小火车程序动画 运维Shell脚本小试…

【系统架构】系统架构设计基础知识

导读&#xff1a;本文整理关于系统架构设计基础知识来构建系统架构知识体系。完整和扎实的系统架构知识体系是作为架构设计的理论支撑&#xff0c;基于大量项目实践经验基础上&#xff0c;不断加深理论体系的理解&#xff0c;从而能够创造新解决系统相关问题。 目录 1、软件架…

高速信号处理板资料保存:383-基于kintex UltraScale XCKU060的双路QSFP+光纤PCIe 卡设计原理图

基于kintex UltraScale XCKU060的双路QSFP光纤PCIe 卡 一、板卡概述 本板卡系我司自主研发&#xff0c;基于Xilinx UltraScale Kintex系列FPGA XCKU060-FFVA1156-2-I架构&#xff0c;支持PCIE Gen3 x8模式的高速信号处理板卡&#xff0c;搭配两路40G QSFP接口&#xf…

PyQt5入门2——添加一个画布并且显示特定的图片

PyQt5入门2——添加一个画布并且显示特定的图片 学习前言使用到的PyQt5类实例使用1、窗口构建a、构建基础类b、读取已有的图片并且显示 2、主程序运行 全部代码 学习前言 搞搞可视化界面哈&#xff0c;虽然不一定有用&#xff0c;但是搞一下。 使用到的PyQt5类 创建画布需要…

MapReduce YARN 的部署

1、部署说明 Hadoop HDFS分布式文件系统&#xff0c;我们会启动&#xff1a; NameNode进程作为管理节点DataNode进程作为工作节点SecondaryNamenode作为辅助 同理&#xff0c;Hadoop YARN分布式资源调度&#xff0c;会启动&#xff1a;ResourceManager进程作为管理节点NodeM…

蓝桥杯2023年第十四届省赛真题-更小的数--题解

目录 蓝桥杯2023年第十四届省赛真题-更小的数 题目描述 输入格式 输出格式 样例输入 样例输出 提示 【思路解析】 【代码实现】 蓝桥杯2023年第十四届省赛真题-更小的数 时间限制: 3s 内存限制: 320MB 提交: 895 解决: 303 题目描述 小蓝有一个长度均为 n 且仅由数字…

【Qt-17】Qt调用matlab生成的dll库

matlab生成dll库 1、matlab示例代码 function BDCube(x,y)[x,y,z] cylinder(x,y);t1 hgtransform;s1 surf(3*x,3*y,4*z,Parent,t1);grid onview(3)shading interp end 2、matlab环境配置 首先检查自己的mcc编译器是否可用&#xff0c;输出以下命令&#xff1a; &#x…

无头单向非循环链表(详解)

无头单向非循环链表 链表的种类的简单介绍链表的定义typedef的运用 节点的创建遍历头插尾插头删尾删查找节点位置任意位置插入任意位置删除 链表的种类的简单介绍 链表的种类有很多 1.分有头链表和无头链表 2.分循环链表和非循环链表 3.分单向链表和双向链表 这里的话&#xff…