ES6----generator

2020.12.9 16:44

01.generator(生成器)

  • generator(生成器)是一个函数
  • generator 函数是 ES6 提供的一种异步编程解决方案
  • generator 函数有多种理解角度。从语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态

02.generator函数和普通函数的区别

书写格式

  • 普通函数:function generator(参数){代码...}
  • 生成器函数:function* generator(参数){代码...} 注意*
  • 函数体内部使用yield语句,定义不同的内部状态(yield在英语里的意思就是“产出”)
  • ES6没有规定,function与函数名之间的星号,写在哪个位置。这导致下面的写法都能通过。
function * generator(a,b){ ··· yield ··· }

function *generator(a,b){ ··· yield ··· }

function* generator(a,b){ ··· yield ··· }

function*generator(a,b){ ··· yield ··· }

与普通函数的对比:

//普通函数
function generator(a,b){	
	alert(a);
	alert(b);
}
generator(5,10);//普通函数调用后会连续弹出a和b

//generator函数
function *generator(a,b){
	alert(a);
	
	yield;

	alert(b);
}
let genObj=generator(5,10);//函数名()不能直接调用 实际上返回了一个对象
console.log(genObj instanceof Object);//true
genObj.next();//调用一次只会弹出a,因为遇到yield停止了
genObj.next();//再调用一次才会弹出b

执行过程中

  • 普通函数:普通函数在执行过程中,如果没有遇到return语句(函数末尾如果没有return,就是隐含的return undefined),控制权无法交回被调用的代码(执行过程中不能停止)
  • 白话理解:普通函数在执行过程中不能停止
  • 生成器函数:生成器函数在执行过程中除了return语句,还可以用yield返回多次
  • 白话理解:生成器函数在执行过程中可以停止(等待某件事情完成),再执行(剩余部分)

调用

  • 调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对
  • 下一步,必须调用遍历器对象的next方法

Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行


03.yield

  • yield可以穿参数也可以返回

1.传参:

function *show(){
    alert("a");

    let a=yield;

    alert("b");

    alert(a);//5
}
let gen=show();

gen.next(12);//"a"
gen.next(5);//"b",5
//会依次弹出"a","b",5

简单分析:
第一次调用next,只执行如下代码

function *show(){
    alert("a");

    yield;//因为碰到yield所以停止执行

第二次调用next,执行如下代码

 	let a;//第二次调用gen.next(5);传递的参数5实际上就赋给了a

    alert("b");

    alert(a);//所以弹出a的值是5
}

给yeild之前的部分传参(和普通函数穿参一样)
function *show(参数1,参数2){ 参数1和参数2在这里使用 yield ··· }
let gen=show(参数1,参数2);

如果函数前漏掉 *

  • 就是普通函数
  • 如果有yield会报错, ReferenceError: yield is not defined
  • yield 只能在Generator函数内部使用

总结:第一次调用next无法给yield传参,第二次调用才能成功传参,给yield之前的部分传参和给普通函数传参相同

2.返回:

function* show(){
    alert('a');

    yield 12;

    alert('b');
	
	//如果最后一步想要返回值只能return
	//return 55;
}
let gen=show();

let res1=gen.next();
console.log(res1);//{value:12,done:false} done,完成的,值为false表示函数未执行完

let res2=gen.next();
//不写return 55输出{value:undefined,done:true} 值为true表示函数已执行完
//写return 55输出{value:55,done:true}
console.log(res2)

通过做菜步骤来类比yield:

步骤:买来的菜==>清洗==>洗好的菜==>==>切好的菜==>==>炒好的菜
function* Vegetables(v){//传入买来的菜v
   
  	let x=`洗好的${v}`;//1.在这里清洗(中间步骤),操作后x就是洗好的菜(中间结果)
   
   				//2.遇到yield,停止执行,返回x==>洗好的菜,这里是第一步,整个过程未完成,对应{value:'洗好的菜',done:false}
    let y=yield x;//3.let y=x 这时y的值是洗好的菜

    y=='洗好的菜'?y='切好的菜':y='';//4.在这里切菜(中间步骤),操作后y就是切好的菜(中间结果)

				//5.遇到yield,停止执行,返回y==>切好的菜,这里是第二步,整个过程未完成,对应{value:'切好的菜',done:false}
    let z=yield y;//6.let z=y 这时z的值是切好的菜
    
    z=='切好的菜'?z='炒熟的菜':z='';//7.在这里炒菜(最终步骤),操作后z就是炒好的菜(最终结果)
    
    return z;	//8.return返回z,这里是第三步,整个过程已完成,对应{value:'炒熟的菜',done:true}
}
let veg=Vegetables('菜');
console.log(veg);

let res1=veg.next();//第一次调用会执行1和2==>传入参数,操作后返回第一步操作产生的中间结果
console.log(res1);//{value:'洗好的菜',done:false}
let res2=veg.next(res1.value);//第二次调用会执行3,4,5==>传入第一步产生的中间结果,操作后返回第二步操作产生中间结果
console.log(res2);//{value:'切好的菜',done:false}
let res3=veg.next(res2.value);//第三次调用会执行6,7,8==>传入第二步产生的中间结果,操作后返回第三步操作产生最终结果
console.log(res3.value);//{value:'炒熟的菜',done:true}

console.log(veg);

运行结果:
在这里插入图片描述

部分内容参考自:参考1,参考2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值