ES6学习笔记(十五)Generator函数

激光光束质量评估与光斑尺寸计算:从理论到MATLAB实践 本文详细解析激光光束质量评估与光斑尺寸计算的理论基础及MATLAB实践方法,重点介绍M²因子的测量与应用。通过高斯光束模型、CCD成像法和MATLAB算法实现,帮助读者掌握从理论到实践的完整流程,提升激光系统调试与评估能力。 阅读详情

Generator函数是ES6中提供的一种异步解决方案,该函数同时也可以用来部署遍历器。


Generator函数的使用


Generator函数和普通的函数不一样,其function和函数名之间有个*,函数体内部用yield表达式来定义不同的状态。

function* gen(){

    yield 1;

    yield 2;

    yield 3;

}

上面代码即为一个Generator函数,与普通函数一样,Generator函数也是在函数名后面加括号传入参数来调用参数的,但函数不会立即执行,会生成一个迭代器控制这个Generator函数的执行,需要使用next才会继续执行,且是执行到yield表达式后的那一句停止,等待下一个next。

function* gen(){

    yield 1;

    yield 2;

    yield 3;

}

var g=gen()

g.next() // {value: 1, done: false}

g.next() // {value: 2, done: false}

g.next() // {value: 3, done: false}

g.next() // {value: undefined, done: true}

如上面代码所示,每次调用next都会让函数往后执行,且返回一个对象,value为yield表达式后面的内容,done表示遍历是否结束,为true时就结束。

yield表达式


yield表达式是Generator函数中的暂停标志,若后面没有yield表达式,有return语句时,执行到return语句,返回value为return后面的内容的对象,没有return语句时,返回value为undefined的对象,done都为true。如果在两个yield表达式中间有return语句,则done会提前变为true。

function* gen(){
    yield 1;
    yield 2;
    return 3;
    yield 4;
}

var g=gen();

g.next(); // {value: 1, done: false}

g.next(); // {value: 2, done: false}

g.next(); // {value: 3, done: true}

g.next(); // {value: undefined, done: true}

上面代码可以看到,因为提前return了,所以在value为3时done就为true了,不会执行到下面的yield 4。

若yield后面没有任何代码,则等同于yield undefined;

function* fn(){
    yield;
}

//等同于

function* fn(){
    yield undefined;
}

若yield表达式后面是一个表达式,那么会在next语句执行到这一句时才进行求值,即惰性求值。

function* gen() {

  yield  123 + 456;

}

像上面代码中,123+456就是在执行到这一句时才求值的。

当然,Generator函数里面可以没有yield语句,此时的Generator函数就变成一个暂缓执行的函数,当调用next时就会执行整个函数,但没调用和next之前,函数是不会执行的。

function* gen(){

    console.log('no yield');

}

var g=gen()

g.next();
// {value: undefined, done: true}

//  no yield

要注意的是,yield表达式只能在Generator函数中使用,在其他地方使用会报错。

(function (){

  yield 1;

})()

// Uncaught SyntaxError: Unexpected number

即使在Generator函数中,若在该函数中再嵌套了一个非Generator函数,而yield语句又在这个函数里面,则也会报错。

function* gen() {

    let arr = [1, 2, 3];

    arr.map(function(val) {

        yield val;

    })

}

// Uncaught SyntaxError: Unexpected identifier

上面代码中,yield语句实际上是在map参数中的函数的,而该函数不是一个Generator函数,所以在声明函数的时候就报错了。

另外,yield若要用在另一个表达式中,必须放在圆括号内,否则会报错。

function* gen(){
    console.log(2+yield 3 );
}

// Uncaught SyntaxError: Unexpected identifier

function* gen(){
    console.log(2+(yield 3));
}

// 不报错

实际上,关于yield的位置,可以参考赋值表达式的位置,使用a=3这个例子来看,当某个位置可以使用a=3时,就可以直接写上yield表达式,如果不行,可以将yield表达式写在括号内。如下代码:

var a, b;

a = 3; // 合法
b = 2 + a = 3; // 不合法
b = 2 + (a = 3); // 合法

yield 3; // 合法
a = 2 + yield 3; // 不合法
a = 2 + (yield 3); // 合法

此外,yield和=运算符一样是右结合的,看如下代码

yield yield yield 3;

//等同于

yield( yield ( yield 3) );

Generator的方法


Generator函数返回一个遍历器,该遍历器有三个方法使函数走出“冻结”的状态。

next方法

该方法使Generator函数执行到下一条yield语句,若之后没有yield语句,则执行到函数尾部,第一个次调用next时算启用Genertor函数。

该方法返回一个有value属性和done属性的对象,value属性的值为yield表达式后的内容,done表示遍历是否已经结束。

function* gen(){
    yield 1;
    yield 2;
    return 3;
}

var g=gen();

g.next()

// {value: 1, done: false}

g.next()

// {value: 2, done: false}

g.next()

// {value: 3, done: true}

g.next()

// {value: undefined, done: true}

next方法的参数是yield表达式返回的值,第一个调用的next方法等同于启用Generator函数,所以并不会把参数给任一个yield表达式作为返回值,而后面的next方法就一次给yield表达式返回值。

function *gen(){
    var a=yield 2;
    var b=yield 3;
    console.log(a,b);
}
var it=gen();
it.next();
it.next(1);
it.next(2);
it.next(3);

// 1  2

如上代码,第二个next方法的参数1作为第一个yield表达式yield 2的返回值赋值给变量a,而第三个next方法的参数2作为第二个yield表达式yield 3的返回值赋值给变量b,所以最后打印出来的结果是1  2。

throw方法

该方法会在Generator函数体外抛出一个错误,在函数体内处理。

function* gen(){
    try{
        yield;
    }catch(e){
        console.log(`Generator内部  ${e}`);
    }
}

var g=gen();

g.next();

try{
    g.throw('error');
}catch(e){
    console.log(`Generator 外部  ${e}`)
}

// Generator内部  error

上面代码可以看到,最后throw抛出的错误被Generator函数内部的catch捕获了。同时也可以看到,throw方法的参数被catch获取到了,若没有传入参数,catch获取的是undefined。

若Generator方法内部没有try catch语句,那么错误要在外部捕获

function* gen(){
    yield;
}

var g=gen();

g.next();

try{
    g.throw('error');
}catch(e){
    console.log(`Generator 外部  ${e}`)
}

// Generator 外部  error

若内部和外部都没有部署try...catch语句,那么将会报错。

function* gen(){
    yield;
}

var g=gen();

g.next();

g.throw('error');

// Uncaught error

要注意的是,throw方法使用时会执行下一条yield语句,即顺带执行一条next方法

var gen = function* gen(){
  try {
    yield console.log('a');
  } catch (e) {

// ...  

}

  yield console.log('b');

  yield console.log('c');}

var g = gen();

g.next() // a

g.throw() // b

g.next() // c

上面代码中,throw方法抛出错误的同时执行了下一条yield语句console.log(‘b’),因为是在try...catch语句中抛出错误的,所以不影响下面语句的执行。

return方法

该方法返回给定的值并终结函数的遍历。即返回一个value为传入的参数,done为true的对象。

function* gen(){
    yield 1;
    yield 2;
    return 3;
}

var g=gen()

g.next()

// {value: 1, done: false}

g.return(4)

// {value: 4, done: true}

g.next()

// {value: undefined, done: true}

若Generator函数中有try...finally语句,则return方法使用后会等到finally块内的语句执完后才停止遍历。return方法的参数作为最后一次遍历返回的对象的value值。

function* gen(){
    yield 1;
    try{
        yield 2;
        yield 3;
    }finally{
        yield 4;
        yield 5;
    }
    yield 6;
}

var g=gen()

g.next()

// {value: 1, done: false}

g.next()

// {value: 2, done: false}

g.return(10)

// {value: 4, done: false}

g.next()

// {value: 5, done: false}

g.next()

// {value: 10, done: true}

g.next()

// {value: undefined, done: true}

上面代码中,在使用return方法后返回了value为finally语句中第一个yield表达式后的值的对象,且done为false,说明遍历还未结束。

return()除了可以手动调用外,还可以在每次迭代的末尾被任何消耗迭代器的ES6构件自动调用,如for...of和扩展预算符...。

 

yield*表达式


要在一个Generator函数里面调用另一个Generator函数,像普通函数一样调用是无效的。因为这样的调用并没有让Generator函数开始执行。

function* foo() {
  yield 'a';
  yield 'b';
}

function* bar() {
  yield 'x';
  foo();
  yield 'y';
}

for (let v of bar()){
  console.log(v);
}

// "x"

// "y"

通过使用yield*表达式,就能在一个Generator函数里面调用另一个Generator函数。

function* bar() {
  yield 'x';
  yield* foo();
  yield 'y';
}

function* foo() {
  yield 'a';
  yield 'b';
}

for (let v of bar()){
  console.log(v);
}

// "x"

// "a"

// "b"

// "y"

上面代码的过程是这样的,我们知道for...of实际上是调用了迭代器的next方法来实现遍历的,这里首先调用了bar()创建一个迭代器,然后yield*把迭代器实例控制委托给了foo(),所以在输出"x"后,下一个是"a",因为此时控制的是foo而非bar,而一旦迭代器消耗了整个foo迭代器,即将整个Generator函数执行完,就会将委托还给bar。

实际上,yield*表达式后面不只是可以放另一个Generator函数,只要是有Iterator接口的结构,都可以放在其后。yield*其实是表示遍历后面的带Iterator的结构。

function* gen(){

    yield* [1,2,3];

}

//等同于

function* gen(){

    for (let i of [1,2,3])

        yield i;

}

var g=gen();

g.next()

//{value: 1, done: false}

g.next()

//{value: 2, done: false}

g.next()

//{value: 3, done: false}

g.next()

//{value: undefined, done: true}

由此可以看出,yield*表达式其实就是用一个for...of来遍历后面的结构,同上,字符串也同样可以。

function* gen(){

    yield* 'yield';

}

var g=gen()

g.next()

// {value: "y", done: false}

g.next()

// {value: "i", done: false}

g.next()

// {value: "e", done: false}

g.next()

// {value: "l", done: false}

g.next()

// {value: "d", done: false}

g.next()

// {value: undefined, done: true}

通过使用yield*表达式调用本身,我们可以构造递归委托,如下代码

function* gen(val){
    if(val>1){
    	console.log(`val : ${val}`);
        val=yield *gen(val-1);
    }
	return val;
}
var out=gen(3);
out.next(); // val : 3
out.next(); // val : 2

作为对象的Generator函数写法


let obj = {

  myGeneratorMethod: function* () {

// ···  

}};

Generator函数的一般写法如上代码,但也可以简写为下面的代码

let obj = {

  * myGeneratorMethod() {

    //···

  }};

Generator函数的this


Generator函数返回的遍历器是Generator函数的实例,会继承Generator函数的原型,但要注意的是,函数返回的是遍历器对象,不是this对象。

function* g() {
  this.a = 11;
}

let obj = g();

obj.next();

obj.a // undefined

上面代码中,函数g中在this对象上声明赋值了一个属性a,但使用obj那不到这个a。

同时,Generator函数不能使用new运算符一起使用,否则会报错。

function* gen(){
    yield 1;
    yield 2;
}

new gen()

// Uncaught TypeError: gen is not a constructor

上面代码可以看到,报错提示gen不是一个构造函数。


参考自阮一峰的《ECMAScript6入门》

           Kyle Simpson的《你不知道的JavaScript 下卷》


ES6学习笔记目录(持续更新中)

 

ES6学习笔记(一)let和const

ES6学习笔记(二)参数的默认值和rest参数

ES6学习笔记(三)箭头函数简化数组函数的使用

ES6学习笔记(四)解构赋值

ES6学习笔记(五)Set结构和Map结构

ES6学习笔记(六)Iterator接口

ES6学习笔记(七)数组的扩展

ES6学习笔记(八)字符串的扩展

ES6学习笔记(九)数值的扩展

ES6学习笔记(十)对象的扩展

ES6学习笔记(十一)Symbol

ES6学习笔记(十二)Proxy代理

ES6学习笔记(十三)Reflect对象

ES6学习笔记(十四)Promise对象

ES6学习笔记(十五)Generator函数

ES6学习笔记(十六)asnyc函数

ES6学习笔记(十七)类class

ES6学习笔记(十八)尾调用优化

ES6学习笔记(十九)正则的扩展

ES6学习笔记(二十)ES Module的语法

 

 

 

深度学习|卷积神经网络 介绍卷积神经网络基本理论,包括卷积层、池化层和全连接层,并阐述LeNet卷积神经网络的构建过程。 阅读详情

相关推荐

AirSim中图像API的应用

解析Airsim图像获取保存的api

fegxg的博客 1605

JavaScript中 Generator 函数详解

Generator 函数是 ES6 提供的一种异步编程解决方案。它既是一个生成器,也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器 Iterator 对象,可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。function 关键字和函数之间有一个星号(*),且内部使用 yield 表达式,定义不同的内部状态;调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object);...

明天也要努力的博客 1855

借助OSS搭建在线教育视频课程分享网站-阿里云的课程体验和记录

阿里云的《搭建在线教育网站》免费课程里面讲的啥,我点进去看了看

LegendNoTitle的博客 3023

js中Generator函数详解

如果说 Promise 是为了解决回调地狱的难题出现的,那么 Generator 就是为了解决异步问题而出现的。普通函数,如果调用它会立即执行完毕;Generator 函数,它可以暂停,不一定马上把函数体中的所有代码执行完毕,正是因为有这样的特性,它可以用来解决异步问题。定义一个 Generator 函数,定义的方式和定义一个普通函数是类似的,不同之处在于它在 function 和函数名之间有一个*号。Generator 函数返回是一个迭代器对象,需要通过 xx.next 方法来完成代码执行。

月光晒了很凉快的博客 7013

解决Surface更新后Bitlocker无限循环的问题

在Surface系统更新以后,出现要求输入Bitlocker恢复密钥的问题。已经输入正确密钥以后,依然无法正常进入Windows操作系统,一旦重启依然循环Bitlocker要求输入密钥的界面。 一旦到登录界面,点击“登录”之后又跳转回登录界面.,但就是无法进入桌面。 解决方案: 拒绝暴力重装!这个问题是Bitlock把盘给锁了,所以要解锁 重启之后,直接点击右下角“跳过这个驱动器” 选择“疑难解答”,然后进入命令提示符 先查看判断现在是不是被锁了: 输入: manage-bde -status c

premierapp的博客 1万+

bcftools实战指南:从VCF文件处理到变异分析全流程解析

在基因组数据分析中,VCF(Variant Call Format)文件是存储基因序列变异信息的标准格式,广泛应用于群体遗传学和生物信息学研究。其核心原理是通过结构化文本记录SNP、INDEL等变异位点的基因型、质量值和注释信息。掌握高效处理VCF文件的技术,对于提升变异检测、数据清洗和下游分析的工作流效率具有重要价值。在生物信息学工具生态中,bcftools作为处理VCF/BCF文件的瑞士军刀,通过模块化设计实现了数据查询、过滤、统计和格式转换等核心功能。其流式处理架构支持管道化操作,能有效应对海量基因组

weixin_29081703的博客 322

es6 Generator函数

Generator

m0_67521703的博客 200

深入AOSP构建系统:从BUILD_FINGERPRINT的生成逻辑,看如何定制你的Android设备标识

本文深入解析AOSP构建系统中的设备指纹生成机制,详细介绍了BUILD_FINGERPRINT的生成逻辑及其在Android设备中的关键作用。通过分析多个指纹属性的区别与联系,以及如何定制设备标识,帮助开发者更好地理解和掌握Android系统构建过程。

weixin_27017211的博客 217

ES6之Generator函数(function*)

文章目录ES6之Generator函数(function*)含义:特征:yield表达式与Iterator接口的关系next方法的参数for...of...循环Generator.prototype.throw() ES6之Generator函数(function*) 含义: Generator函数是ES6提供的一种异步解决方案 Generator函数是个状态机,封装了多个内部状态(yield),还是一个遍历器对象生成函数(next)(yield生成状态,next进行状态的流转) 特征: functi

zuxy_007的博客 137

SPMI协议学习总结

SPMI(System Power Management Interface)是由MIPI(Mobile Industry Processor Interface)联盟定义的一种硬件接口标准,它主要用于移动设备中,连接SoC(System on Chip)处理器系统的集成电源控制器与一个或多个电源管理IC(PMIC),以实现精确的电源管理

歌颂苦难的行为是无耻的; 1082

静态时序分析—门控时钟检查(clock gating check)

clock gating check的条件与类型

m0_61544122的博客 9606

Generator函数、yield语句

Generator函数、yield语句

weixin_46544034的博客 395

MicroChip的SmartFusion2的M2S090芯片的全流程开发环境搭建和Demo设计

MicroChip的SmartFusion2的M2S090芯片的全流程开发环境搭建和Demo设计

qq_45806640的博客 455

ES6学习笔记(十五)Generator函数的异步应用

1.传统方法 ES6 诞生以前,异步编程的方法,大概有下面四种。 回调函数 事件监听 发布/订阅 Promise 对象 Generator 函数将 JavaScript 异步编程带入了一个全新的阶段。 2.基本概念 异步 所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。 ...

weixin_30576827的博客 168

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

ES6(十五)Generator

Generator 简介 基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。 跟普通函数的区别 function关键字与函数名之间有一个星号; 函数体内部使用yield表达式,定义不同的内部状态。 Generator函数不能跟new一起使用,会报错。 functio

weixin_44959855的博客 870

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

初学ES6笔记十五Generator 函数的异步应用

本人的笔记内容来自于[阮一峰老师的ECMAScript 6 详细内容请看(http://es6.ruanyifeng.com/#docs/array) Generator 函数的异步应用 一、基本概念 "异步",就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。 相应地,连续的执行就叫做同步。由于是连续执行,不能插入其...

weixin_44072887的博客 267

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

第十五节:有一种特殊的函数叫:Generator函数

今天我们来学习ES6给我们带来的一种新函数,在学习它之前,前端君希望你已经阅读并初步了解了上一节的内容:iterator遍历器。因为本节的内容,是建立在i...

qq_24520459的博客 192

ES6学习笔记(二)(feat阮一峰ES6教程)

**内容简介:** 十二、Symbol 十三、Set 和 Map 数据结构 十四、Proxy 十五、Reflect 十六、Promise 对象 十七、Iterator 和 for...of 循环 十八、Generator 函数的语法 十九、Generator 函数的异步应用 二十、async 函数 二十一、Class 的基本语法 二十二、Class 的继承 二十三、Module 的语法 二十四、Module 的加载实现 二十七、异步遍历器

weixin_43995977的博客 861

ES6--Promise、Generator及async

ES6诞生以前,异步编程的方法,大概有如下四种:回调函数、事件监听、发布/订阅、Promise对象;ES6中,引入了Generator函数;ES7中,async更是将异步编程带入了一个全新的阶段。十四、Promise对象​ Promise,就是一个对象,用来传递异步操作的消息,避免了层层嵌套的回调函数。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进

李刚的学习专栏 7857

es6学习笔记整理(十五)Generator生成器

基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。 Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数一个状态机,封装了多个内部状态。 执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。 形式上,Gen...

youyouyouyou44的博客 205

【ES6】第十五节:有一种特殊的函数叫:Generator函数

转自:微信公众号—— web前端教程           今天我们来学习ES6给我们带来的一种新函数,在学习它之前,前端君希望你已经阅读并初步了解了上一节的内容:iterator遍历器。因为本节的内容,是建立在iterator遍历器知识的基础上。           如果是新来的童鞋,或者您还未了解iterator遍历器,我希望你可以先学习上一节的内容,点击可查看:第十四节iterator...

weixin_39068791的博客 217

es6 Generator (十五)

Generator函数基本概念: function*  yield next函数的用法 yield

chenna1102cn的博客 286

ES6部分简略总结

一、数字拓展 1、Number.isNaN——判定一个数字是否是NaN 全局中的isNaN,会进行数据类型的转换 先尽可能转为数字 再判定 Number.isNaN, 不会进行数据类型的转换 参数只要不是数字类型 就为false 2、Number.isFinite——判定一个值是否是有限的 全局中的isFinite,会进行数据类型的转换 先尽可能转为数字 再判定 Number.isFinite, ...

静水流深de博客 704

前端入门学习笔记(二十五)JavaScript入门(八)函数闭包(以及坑)、generator(函数多个返回值)

函数闭包 在面向对象的程序设计语言里,比如Java和C++,要在对象内部封装一个私有变量,可以用private修饰一个成员变量。 在没有class机制,只有函数的语言里,借助闭包,同样可以封装一个私有变量。我们用JavaScript创建一个计数器: 'use strict'; function create_counter(initial) { var x = initial || 0;...

TUTsmile的博客 289

ES6面试、复习干货知识点汇总,【面试必会】

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】世界上只有一种真正的英雄主义就是在认清生活真相之后仍然热爱它有帮助,可以添加下面V无偿领取!(备注:前端)**[外链图片转存中…(img-fjX1y6uI-1710772070257)]开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】世界上只有一种真正的英雄主义就是在认清生活真相之后仍然热爱它。

m0_60634964的博客 1003

ES6 学习笔记

推荐前端开发学习javaScript网站 https://zh.javascript.info/object-basics?map 根据阮一峰阮一峰ES6学习整理 .koa2推荐阅读 Nodejs API文档 vuejs API文档 eslint vue Eslint 我觉得别人整理的不错的ESLint javascript设计模式推荐阅读 Typescript库 Babel...

gsy_study的博客 588
上一篇: ES6学习笔记(十四)Promise对象
下一篇: ES6学习笔记(十六)async函数
前端小黑
博客等级 码龄9年 148粉丝 222原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值