ES6学习——生成器(Generators):概念介绍

73 篇文章 23 订阅

应该说生成器是ES6中最大的特色,但这个概念在其他语言中早就有实现的了,譬如C#,python。简单解释生成器就是一种能中断和恢复自己的函数,具体的解释可以参考【探秘ES6】系列专栏(三):生成器,这篇文章解释的比较详细,下面有些内容我就直接使用这篇文章的了。

生成器的两点特征:

  • 生成器函数以function*开头;
  • 在生成器函数中,yield是一个关键字,如同return。yield可以多次使用,作用是中断生成器,而在需要的时候可以恢复生成器的执行。
从上面两点可以看出,生成器仍然是个函数,这个星号到底是挨着function写(function* funcName(){})还是挨着函数名(function *funcName(){})字写,语法上都是没错的,网s上也有很多争论,看自己喜好了。第二点中的关键字yield只能使用在生成器中,普通函数中是不能用的。

规范中关于生成器的内容在14.4,25.2和25.3,有兴趣的自己可以去看。

看个生成器的例子:
function* quips(name) {
  yield "hello " + name + "!";
  yield "i hope you are enjoying the blog posts";
  if (name.startsWith("X")) {
    yield "it's cool how your name starts with X, " + name;
  }
  yield "see you later!";
}

> var iter = quips("jorendorff");
  [object Generator]
> iter.next()
  { value: "hello jorendorff!", done: false }
> iter.next()
  { value: "i hope you are enjoying the blog posts", done: false }
> iter.next()
  { value: "see you later!", done: false }
> iter.next()
  { value: undefined, done: true }

对于普通quips(),它会马上执行直到出现返回或异常抛出等情况。在生成器函数中,调用方式是类似的:quips("jorendorff"),但是它不会马上执行。取而代之的是,它会返回一个已暂停的生成器对象(如上述代码的iter)。你可以把生成器对象看成是一个被暂停的函数调用。要特别说明的是生成器对象在生成器函数开始时被冻结,即第一行代码执行之前。

每当调用生成器对象的.next()方法时,函数恢复运行直至遇到下一个yield表达式,其作用是用于迭代。因此iter.next()的目的是为了返回不同的字符串。在最后的iter.next()中,使用done:true表示结束。到达函数末端意味着返回的结果是undefined,所以代码片段中使用value: undefined结尾。

从技术角度来看,每当生成器执行yield操作时,它的堆栈帧包括本地变量、参数、临时值等都会从堆中被移出。但是生成器对象会保留(拷贝)对该帧的引用,所以.next()可以重新激活它然后继续执行。这里特别要说明的是,生成器不是线程。当一个生成器执行时,它与其调用者都处于同一个线程,是按次序执行而不是并行运行。

通过上面的例子可以看出,生成器的使用方法和迭代器差不多,没错,生成器就是个迭代器,他们之间有原型继承关系,这也是生成器的一大特点。所有适用于迭代器的语法都适用于生成器。

生成器还有一个特点就是可以把异步过程同步化,后面在讲生成器和Promise的时候会详细说明。

我们在看一下生成器的实质是什么?通过这个http://babeljs.io/repl网站可以看看在ES6中的生成器是如何转换成ES5中的语法:
ES6生成器代码:
function* genFunc(){
  yield 1;
  yield 2
  
}

var g = genFunc();

转成ES5的语法:
"use strict";

var marked0$0 = [genFunc].map(regeneratorRuntime.mark);
function genFunc() {
  return regeneratorRuntime.wrap(function genFunc$(context$1$0) {
    while (1) switch (context$1$0.prev = context$1$0.next) {
      case 0:
        context$1$0.next = 2;
        return 1;

      case 2:
        context$1$0.next = 4;
        return 2;

      case 4:
      case "end":
        return context$1$0.stop();
    }
  }, marked0$0[0], this);
}

var g = genFunc();
从上面转换的过程可以看到,生成器就是个状态机,它内部是有一些状态在控制其运行过程。


*以上全部代码在Chrome 48下通过测试

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值