ES6生成器总结

一、生成器的个人理解

首先什么是生成器:生成器就是Es6中用来设置迭代器的一个函数,我们就可以这样理解:生成器最终生成的就是迭代器。

生成器:生成器中存在一个iterator接口,也就是说,生成器本身是可以进行迭代的,也就是创造出一个生成器,就相当于创建一个迭代器。关于生成器的用途,对于一些没有设置迭代器接口的数据类型,我们可以使用生成器来自定义生成一个迭代器,从而进行迭代。
以上便是我对于生成器本身的理解,下面讲解具体的语法。

二、生成器的一些属性
//生成器的声明
<script>
function* generator(){

  }
let test = generator();
 console.log(test);
</script>
//生成器中的yield关键字
<script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());
    console.log(test.next());

  </script>

最终结果:

es6代码转非es6 在线工具 es6生成器 实现原理_生成器


解析:由于生成器实例化对象的原型中存在next(),当执行next(),就会根据yield进行迭代。

<script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test[Symbol.iterator]);
  </script>

es6代码转非es6 在线工具 es6生成器 实现原理_generator_02


又是上面的代码可以看出这个生成器存在Symbol.iterator接口,所以可以将其看成一个迭代器

生成器只会在使用初次调用函数的时候执行
<script>
    function* Generator(){
      console.log("初次执行函数");
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    console.log(test.next());
  </script>

执行结果是:

es6代码转非es6 在线工具 es6生成器 实现原理_javascript_03

在生成器中也会有接口,但是他们默认的迭代器是自引用的,所以下面两种迭代方式得到相同的结果
<script>
    function* Generator(){
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test = Generator();
    // for(const x of test){
    //   console.log(x);
    // }
    for(const x of test[Symbol.iterator]()){
      console.log(x);
    }
  </script>

结果是:

es6代码转非es6 在线工具 es6生成器 实现原理_generator_04

生成器对象区分作用域
<script>
    function* Generator() {
      yield 100;
      yield 200;
      yield 300;
      yield 400;
    }
    let test_1 = Generator();
    let test_2 = Generator();
    console.log(test_1.next());
    console.log(test_2.next());
    console.log(test_1.next());
    console.log(test_2.next());
  </script>

解析:生成器是按照游标进行输出的,也就是但是当作用域不同,两者的游标互相不影响。

结果:

es6代码转非es6 在线工具 es6生成器 实现原理_javascript_05

实现yield关键字输出输入
<script>
    function* Generator() {
      console.log(yield 100);
      console.log(yield 200);
      console.log(yield 300);
      console.log(yield 400);
    }
    let test = Generator();
    console.log(test.next("foo"));
    console.log(test.next("bar"));
    console.log(test.next("btz"));
    console.log(test.next('set'));
    console.log(test.next("map"));
  </script>

结果:

es6代码转非es6 在线工具 es6生成器 实现原理_es6代码转非es6 在线工具_06


这里当我们传入第一个的时候,并没有输出,这是当我们执行第一个的next()的时候,相当于去开启执行这个函数,但是这个值并不传给yield,但是当执行第二个yield的时候,这个yield接收到传给的值并输出。

yield*的使用
  <script>
    // function* Generator() {
    //   yield* [1, 2, 3, 4, 5];
    // }
    // let test = Generator();
    // for (const x of test) {
    //   console.log(x);
    // }

    function* Generator(){
      let arr = [1,2,3,4,5];
      for(const x in arr){
        yield arr[x];
      }
    }
    let test = Generator();
    for (const x of test[Symbol.iterator]()){
      console.log(x);
    }
    //1,2,3,4,5
  </script>

以上两个方法进行迭代,都可以得到相同的结果,yiled*就相当于结构的思想。

yield* 的值最终返回的一定是undefined
  <script>
    function* Generator(){
      console.log(yield* [1,2,3,4,5]);;
    }
    let test = Generator();
    for (const x of test[Symbol.iterator]()){
      console.log(x);
    }
  </script>

最终结果:

es6代码转非es6 在线工具 es6生成器 实现原理_生成器_07


其实这里可以这样想yield * [1,2,3,4]就等价于 yield 1;yield 2,yield 3;yield 4;由于没有给yield传值,所以打印出来的是undefined。

yiled实现递归
 <script>
    function* Generator(n) {
      if (n > 0) {
        yield* Generator(n - 1);
        yield n;
      }
    }
    let text = Generator(10);
    for (const x of text) {
      console.log(x);
    }
   //1,2,3,4,5,6,7,8,9,10
  </script>
yiled*后面必须接上一个具有iterator接口的数据类型
<script>
//第一种
    function* gener_1(){
      yield* [1,5,6,3,10];
    }
    function* gener_2(){
      yield* gener_1();
    }
    for(const x of gener_2()){
      console.log(x);
    }
//1,5,6,3,10
  </script>
这里我们实现手写三种迭代接口,这三种从上往下更加规范,简单
<script>
  class Gener {
      constructor() {
        this.value = [1, 2, 3, 4, 5];
      };
      [Symbol.iterator]() {
        let index = 0;
        let value = this.value;
        return {
          next() {
            if (index < value.length) {
              return {
                value: value[index++],
                done: false,
              }
            }
            else {
              return {
                value: undefined,
                done: true
              }
            }
          }
        }
      }
    }
    let test = new Gener();
    for (const x of test) {
      console.log(x);
    }
//第二种
      class Gener{
        constructor() {
          this.value = [1,2,3,4,5];
        }
        *[Symbol.iterator](){
          for(const x of this.value){
            yield x;
          }
        }
      }
      let test = new Gener();
      for (const x of test){
        console.log(x);
      }
  // 第三种
  class Gener{
          constructor(){
            this.value = [1,2,3,4,5];
          }
          *[Symbol.iterator](){
            yield* this.value;
          }
        }
        let test = new Gener();
        for(const x of test){
          console.log(x);
        } 
</script>

这三种最终的结果都是一样的,为什么要设置[Symbol.iteerator],是因为class对象中不可以进行迭代。

return方法
<script>
  function * text(){
    yield* [1,2,3,4,5];
  }
  let g = text();
  console.log(g.return("3"));
  </script>

在这里执行return()的时候,就会返回其中传入return的值,并且将其done设置为true

关于生成器中的throw()
<script>
    function* text() {
      for (const x of [1, 2, 3]) {
        try {
          yield x;
        }
        catch {
          console.log("这是一个错误");
        }
      }
    }
    let test = text();
    console.log(test.next());
    console.log(test.throw("hhhh"));
    console.log(test.next());
    console.log(test.next());
  </script>

解析:这里一般执行throw()的时候,都会伴随着try…catch一起使用。当执行这个throw()函数的时候,就相当于传一个错误,所以就不会执行try中的语句,而是执行catch中的语句。然后不会像return()一样直接退出迭代,throw()会跳过这个进入下一个。

es6代码转非es6 在线工具 es6生成器 实现原理_es6_08


以上便是我对于ES6的生成器的总结,以及自己的理解。总结出来时间已经比较晚了,加油,明天进入面向对象。