1. 什么是生成器Generator
生成器Generator在异步流程中,它可以控制我们的一个异步流程。
我们先看看生成器的一个基础语法:
function * fn(){} 注意:*放在开头或者中间或者结尾都是可以的。
生成器与普通函数不同的第一点就是:普通函数使用 function 声明,而生成器函数使用 function* 声明。
接下来我们再来看几行代码:
1 2 3 4 5 6 7 8 9 10
| function * fn(){ yield "xiaoming"; yield "xiaoli"; yield "xiaohong"; } const people = fn(); people.next(); people.next(); people.next(); people.next();
|
生成器与普通函数不同的第二点就是:在生成器函数内部,有一种类似 return 的语法:关键字 yield。二者的区别是,普通函数只可以 return 一次,而生成器函数可以 yield 多次(当然也可以只 yield 一次)。next()相当于开按钮,yield相当于关按钮。
普通函数,如果没有return语句就会从头到尾执行。
普通函数和生成器函数之间最大的区别,普通函数不能自暂停,生成器函数可以。
2. 生成器Generator的应用例子
例1:
1 2 3 4 5 6 7 8 9 10 11 12 13
| function * fn(){ console.log("A"); yield "xiaoming"; console.log("B"); yield "xiaoli"; console.log("C"); yield "xiaohong"; } const people = fn(); people.next(); people.next(); people.next(); people.next();
|
例2:
在做例2之前,我们需要先注意一点:如果没有在next()方法里面传入参数的话,我们整体的yield语句就是一个undefined。如果你想把yield语句的值更改的话,就通过next()方法传入参数。
1 2 3 4 5 6 7 8 9
| function * fn(x){ var y = yield(x+2); var z = yield(y/3); return (x+y+z); } const it = fn(4); console.log(it.next()); console.log(it.next()); console.log(it.next());
|
- 当执行第一个next()方法的时候,碰到的是一个赋值语句,把右边的值给左边,但是右边的值碰到了yield语句就暂停了。所以就把yield后面的值(x+2)给value,就是6;
- 当执行第2个next()方法的时候,现在可以完成赋值语句了,我们应该把y赋值成yield(x+2)整个的语句,它整个语句的值是一个undefined。然后再执行z的赋值语句,但是遇到第二个yield语句就暂停了,value就输出”undefined/3”=NaN;
- 当执行第三个next()方法的时候,由于yield(y/3)中整个的语句没有传值进来,那么它的整个语句的值是一个undefined,即z就为一个undefined,所以x+y+z=4+undefined+undefined=NaN,所以value的值为NaN。由于一个return语句,表示当前已经执行完了,所以done为true。
例3:
我们接下来再做一个例子,是在next()方法中传入一个值。
1 2 3 4 5 6 7 8 9
| function * fn(x){ var y = yield(x+2); var z = yield(y/3); return (x+y+z); } const it = fn(4); console.log(it.next()); console.log(it.next(6)); console.log(it.next());
|
- 当执行第2个next()方法的时候,执行的是y的赋值语句,整体yield(x+2)语句等于next(6)传入过来的参数6,那么y=6。接着执行z的赋值语句,但是碰到了右边的yield语句又暂停了,所以value的值为y/3 = 6/3 = 2。
- 当执行第3个next()方法的时候,执行z的赋值语句,由于next()方法中没有传值,所以z的值为undefined。所以x+y+z=4+6+undefined = NaN。
如果想要z有值的话,就在第三个next()方法中传入一个值,如it.next(10),那么第三next()方法执行完后打印出来为:x+y+z=4+6+10=20即{value: 20,done: true}
3. erator函数执行返回generator对象,只是说它的用法和iterator一样
for of循环:
generator函数执行返回generator对象,只是说它的用法和iterator一样,iterator可以通过”for of”直接循环出来,不用我们手动.next()执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var arr = [1,2,3]; function * fn(){ console.log("A"); yield "xiaoming"; console.log("B"); yield "xiaoli"; console.log("C"); yield "xiaohong"; } const people = fn(); for(var person of people){ console.log(person); }
|
4. 给普通对象写一个自己的Symbol.iterator
由于普通的对象是没有Symbol.iterator的,如果我们用for of去循环是不好使的。因此我们可以自己写一个Symbol.iterator,然后去循环for of。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var obj = {a: 1}; obj[Symbol.iterator] = function * (){ yield 1; yield 2; return 3; } for(var prop of obj){ console.log(prop); }
|