ES6之Generator函数的语法

generator函数是ES6提供的异步解决方案,跟之前的完全不同。先看看语法:

function* generator() {

yield ‘a’;

yield ‘b’;

return ‘c’;

}

var ge = generator();

console.log(ge.next());//{value: “a”, done: false}

console.log(ge.next());//{value: “b”, done: false}

console.log(ge.next());//{value: “c”, done: true}

Function关键字之后加*内部用yield表达式,相当于这个函数有三个状态a、b、c。调用的时候跟普通函数一样,但是不是执行这个函数,而是返回一个指针对象,也就是iterator Object。当我们调用遍历器对象的next方法的时候,指针向下移动。每次调用next方法,内部指针从函数头部或上一次停下的地方开始执行直到下一个yield或者return 语句。Generator函数就是分段执行,yield表达式就是暂停执行,next方法继续往下执行。

打印next,可以看见返回的是value和done,这跟iterator是一样的,当done是true的时候表示遍历结束了,结束之后继续调用则都是undefined和true。要注意的是,如果没有return,那么返回对象的值就是undefined。

Yield和return的区别就是yield可以多个,return只能一个,yield可以记住位置,return不行。如果generator没有yield,那么这个函数就只是普通的函数,而且是赋值之后还要调用next才会执行的暂缓执行函数。要特别注意,yield表达式只能在generator函数里面,其他全部会报错。

Yield如果放在其他表达式里面,要加圆括号:

console.log(1 + yield); // SyntaxError

console.log(1 + yield 123); // SyntaxError

console.log(1 + (yield));

console.log(1 + (yield 1));

赋值的时候放第一个也不会报错

let a = yield + 1;

let b = 1 + yield;//SyntaxError

函数参数的时候也可以不用圆括号:

function* generator() {

fn(yield 1)

}

Next方法可以携带参数,当作yield表达式返回的值:

function* generator() {

var a = yield ‘a’;

console.log(a);//1

var b = yield ‘b’;

console.log(b);//2

return a + b;

}

var ge = generator();

console.log(ge.next(0));//{value: “a”, done: false}

console.log(ge.next(1));//{value: “b”, done: false}

console.log(ge.next(2));//{value: “3”, done: false}

传参是非常有用的,因为你只有通过这一个方法向内部注入变量,去调整行为。注意,参数表示的是上一个,一定要注意是上一个yield表达式后面的返回值,第一次调用的时候传参是无效的。

刚说过generator是一个生成iterator对象的函数,所以可以直接使用for of,不需要调用next方法:

function* generator() {

yield 1;

yield 2;

yield 3;

yield 4;

yield 5;

return 6;

}

for(let i of generator()){

console.log(i);

}//1 2 3 4 5

当next返回的done是true的时候,循环会终止,且不包含返回的对象,所以return的语句不会在循环中。

通过这个特性,可以做好多循环的拓展,比如让json可以循环:

let obj = {a: 1, b: 2, c: 3};

function* fn(obj) {

let keys = Reflect.ownKeys(obj);

for(let key of keys){

yield [key, obj[key]]

}

}

for(let [key, val] of fn(obj)){

console.log(key + val);

}

可以让很多不能循环的通过generator函数加上遍历接口。

Generator.prototype.return() :

除了内部return终止generator函数之外,还有一个外部的return方法:

function* generator() {

yield 1;

yield 2;

yield 3;

}

let ge = generator();

console.log(ge.next());//{value: 1, done: false}

console.log(ge.return());//{value: undefined, done: true}

console.log(ge.next());//{{value: undefined, done: true}

且最后一个返回的是return的参数,如果没有参数则是undefined。

Yield表达式主要是用在generator表达式内部嵌套generator函数的时候,如果我们在generator函数内部嵌套多个generator,那么我们需要手动完成遍历,然后ES6还提供了yield表达式,用来执行内部generator函数:

function* ge1() {

yield ‘a’;

}

function* ge2() {

yield ‘b’;

yield ge1();

yield ‘c’;

}

var gen = ge2()

console.log(gen.next().value); //b

console.log(gen.next().value); //遍历器对象

console.log(gen.next().value); //c

function* ge3() {

yield ‘d’

yield* ge1()

yield ‘e’

}

var gen = ge3()

console.log(gen.next().value); //d

console.log(gen.next().value); //a

console.log(gen.next().value); //e

要注意的是,如果是嵌入使用的generator,最好不要有return语句,如果有就要自己去赋值获取return语句的值。没有return语句相当于内置了for of循环,且有iterator接口的都能被yield*遍历。

Generator的上下文比较特殊,当遇到yield的时候,会暂时退出堆栈,但是不会消失,直到执行next的时候重新加入调用栈。

Generator对于异步的处理显而易见了,当你需要同步执行的时候,调用next就能按顺序执行。

还有一部分关于throw的方法、this、状态机、协程等,个人觉得实在是篇幅太多,有兴趣可以自己去阮一峰大神的ECMAScript去看看,本人也只是通过这本书做一些笔记而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值