前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES6之Generator函数的语法

ES6之Generator函数的语法

作者头像
wade
发布2020-04-23 16:29:04
3620
发布2020-04-23 16:29:04
举报
文章被收录于专栏:coding个人笔记coding个人笔记

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

代码语言:javascript
复制
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如果放在其他表达式里面,要加圆括号:

代码语言:javascript
复制
console.log(1 + yield); // SyntaxError
console.log(1 + yield 123); // SyntaxError
console.log(1 + (yield)); 
console.log(1 + (yield 1)); 

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

代码语言:javascript
复制
let a = yield + 1;
let b = 1 + yield;//SyntaxError

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

代码语言:javascript
复制
function* generator() {
  fn(yield 1)
}

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

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
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可以循环:

代码语言:javascript
复制
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函数加上遍历接口。

代码语言:javascript
复制
Generator.prototype.return() :

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

代码语言:javascript
复制
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函数:

代码语言:javascript
复制
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去看看,本人也只是通过这本书做一些笔记而已。

(完)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 coding个人笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档