Generator 生成器函数

Generator 函数语法

Generator 函数是ES6提供的一个生成器,声明生成器需要在函数名称前加 * 号。

执行Generator函数会返回一个迭代器(是一个对象),在生成器函数内部,通过 yieldyield*,将当前的生成器的控制交给外部,在外部调用 nextreturnthrow 方法在把控制权还给生成器函数,并且还可以给生成器函数传递参数

定义Generator
和普通函数定义时一样,唯一不同就是在function后面添加*,因为ES6中没有明确规定*的位置,所以*号只要在functionfunction name中间都可以

function * sum(){
	yield 1 + 2;
}

yield 和 yield 表达式*
yieldyield* 是在生成器函数内部使用的,生成器通过 yield 向外部返回值。只要生成器调用了 next 方法,就会返回一个 IteratorResult 对象。

  • 遇到 yield 就会暂停执行 并且将 yield 后面的值作为返回对象的 value 属性
  • 下一次调用 next 方法会在继续往下执行,直到遇到下一个 yield ,没有的话,就直到return,并将return后面的值作为value的值
  • 没有return 也value的为undefined
  • ⚠️ yield 只能在Generator函数中,在其他函数会报错
    该对象结构为:
{value:undefined,done:true}

其中,value 表示此次迭代的结果,done 表示是否已经迭代结束。

function* gen(){
	yield 1;
	yield 2;
}
let g = gen();
g.next();//{value:1,done:true}
g.next();//{value:2,done:true}
g.next(); //{value:undefined,done:true}

yield 后面可以不带任何表达式,此时的 value 返回 undefined

function *gen(){
	yield 
}
let g = gen();
g.next(); // {value:undefined,done:true}

生成器通过使用 yield* 表达式可以委托给另外一个可以迭代的对象,包括生成器。

委托给 js 内置的迭代对象

function *fn(){
	yield 1;
	yield* [2,3]
}
let f = fn();
f.next(); //{value:1,done:false}
f.next(); //{value:2,done:false}
f.next(); //{value:3,done:false}
f.next(); //{value:undefined,done:true}

委托给一个生成器

function * sum(){
	yield* fn();
	yield* [4,5]
	yield 6;
}
let s = sum();
s.next(); //{value: 1, done: false}
s.next(); //{value: 2, done: false}
s.next(); //{value: 3, done: false}
s.next(); //{value: 4, done: false}
s.next(); //{value: 5, done: false}
s.next(); //{value: 6, done: false}
s.next(); //{value:undefined,done:true}

如果Generator函数不搭配yield表达式,就只是一个单纯的暂缓函数

function *f(){
	console.log('你好');
}
let g = f();
g.next() //你好

next、return 和 throw 方法
在生成器外部通过这3个方法控制生成器函数内部的执行过程。

next
next中传递参数,第一次传递参数是无用的。

在生成器外部可以给 next 方法传递一个参数,这个参数会被当做上一个的 yield 表达式的返回值,如果不传递参数,那么 yield 表达式返回 undefined

function * say() {
     let a = yield 'hello';
     console.log('a',a);
     let b = yield 'world';
     console.log('b',b);
     let c = yield 'zfpx';
     console.log(c);
 }
 let it = say();
 it.next(100); // 第一次next传递参数 是无意义的
 it.next(200);
 it.next(300);
function *fn(){
	console.log(yield)
	console.log(yield)
	console.log(yield)
}
let f = fn();
f.next(); // 执行第一个 yield 表达式 
f.next("hello"); // 第一个 yield 表达式的返回值是 'hello', 打印出 'hello'
f.next("world"); // 第二个 yield 表达式的返回值是 'world', 打印出 'world'
f.next(); // {value:undefined,done:true}

执行过程

  • 第一次调用next碰到yield就暂停了。此时返回的{value:1,done:false},不会给a赋值
  • 在调用next的时候传入100这时,a就是100

return
return 是结束生成器的,并且返回一个 IteratorResult,其中 donetruevaluereturn 的返回值,默认是 undefined

function * fn(){
	yield 1;
	yield 2;
	yield 3;
}
let f = fn();
f.next(); //{value:1,done:false}
f.return('100'); //{value:'100',done:true}
f.next(); // {value:undefined,done:true}

throw
在生成器外部可以通过给 throw 方法传入一个参数,该参数会由 catch 语句捕获,如果不传入任何参数。catch 语句捕获到的将会是 undefinedcatch 语句捕获到之后会恢复生成器的执行,返回带有的 IteratorResult(只返回 1 次)。

function *g(){
	try{
		yield 1;
		yield 2;
		yield 3;
	}catch(e){
		console.log(e)
	}
}
let a = g();
a.next(); //{value: 1, done: false}
a.throw(new Error("error!")); //Error: error! 
//{value: undefined, done: true}
a.next(); //{value: undefined, done: true}

和 Symol.iterator的关系

Symbol.iterator 是一个函数,就是当前数据结构默认的迭代器生成函数,执行这个函数,就会返回一个迭代器,至于属性名Symbol.iterator,它是一个表达式,返回 Symbol对象的iterator属性,这是预定好的类型为 Symbol 的特殊值,所以要放在[]中

```
const obj ={
	[Symbol.iterator]:function(){
		return {
			next:function(){
				return { value:1 ,done:true}
			}
		}
	}
}
```

没有Symbol.iterator的不可以被for of 遍历,显然 object没有

  • Object 因为不确定那个属性先遍历,那个属性后遍历,需要开发者手动制定。
    原生俱备iterator接口的数据结构
  • Arrary
  • Map
  • Set
  • String
  • TypeArray
  • 函数的 arguments 对象
  • NodeList 对象

Array

  • 原生就有iterator接口,部署在Array实例的Symbol.iterator属性上面
let ary = [1,2,4,5];
let it = ary[Symbol.iterator]()
it.next() //{value: 1, done: false}
it.next() // {value: 2, done: false}
it.next() // {value: 4, done: false}
it.next() // {value: 5, done: false}
it.next() // {value: undefined, done: true}

String

  • 原生就有iterator接口,部署在String实例的Symbol.iterator属性上面
var someString = "hi";
typeof someString[Symbol.iterator]
// "function"

var iterator = someString[Symbol.iterator]();

iterator.next()  // { value: "h", done: false }
iterator.next()  // { value: "i", done: false }
iterator.next()  // { value: undefined, done: true }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值