生成器函数 function*

89 阅读2分钟

前言

很早之前就了解过一点,但日常开发基本都见不到它的身影。今天带大家再学习一遍 function* ,了解一下它的可用场景。

什么是生成器函数

function*  这种声明方式会定义一个生成器函数 (generator function),它返回一个 Generator 对象。

示例:

function* test() {}

生成器函数的特点:

  • 调用生成器函数,并不会马上执行它里面的语句,而是返回一个 Generator 对象(是一个可迭代对象)。
  • 生成器函数在执行时能暂停,后面又能从暂停处继续执行。
  • 调用 Generator 对象的 next() 方法,代码会执行到下一个 yield 语句处并暂停执行,然后返回 yield 表达式的值。

Tip

我们可以从两方面来使用生成器函数。

  1. 利用它返回的可迭代Generator 对象
  2. 通过无限循环和 yield,调用 next() 来生成你想要的数据

使用场景

  1. 利用它返回的可迭代的 Generator 对象,来展平数组

    function* iterArr(arr) {            //迭代器返回一个迭代器对象
      if (Array.isArray(arr)) {         // 内节点
          for(let i=0; i < arr.length; i++) {
              yield* iterArr(arr[i]);   // (*) 递归
          }
      } else {                          // 离开
          yield arr;
      }
    }
    

    Generator 对象是可迭代对象,它的迭代元素是由 yield 返回值组成的。再看上述代码,当 arr 不会数组时,使用 yield 组装到可迭代对象上;反之,继续交给生成器函数去执行。

    遍历这个 Generator 对象

    var arr = ['a', ['b', 'c'], ['d', 'e']];
    for(var x of iterArr(arr)) {
      console.log(x);               // a  b  c  d  e
    }
    
    // 或者将迭代器展开
    var gen = iterArr(arr);
    arr = [...gen];                        // ["a", "b", "c", "d", "e"]
    

    使用递归算法时,我们经常使用 return 来组装我们想要的结果,现在使用 生成器函数 也是可以的。

    上述代码普通函数实现:

    var arr = ["a", ["b", "c"], ["d", "e"]];
    
    function iterArr(arr) {
      let acc = []
      if (Array.isArray(arr)) {
        arr.forEach((item) => {
          // 这里是最终的结果
          acc = [...acc, ...iterArr(item)];
        });
      } else {
        // 递归调用的返回值,用来组装最终的结果
        acc = [...acc, arr];
      }
      return acc;
    }
    
    console.log(iterArr(arr)) // [ 'a', 'b', 'c', 'd', 'e' ]
    

    显然,这里普通函数没有生成器函数用起来方便。

  2. 用生成器函数返回随机数

    function* getRandom(num) {
      while(true) {
        yield (Math.random() * num).toFixed(0)
      }
    }
    
    const getRandomGen = getRandom(10)
    console.log(getRandomGen.next().value)
    console.log(getRandomGen.next().value)
    

    当然用普通函数获取随机数也很容易,此处只为举例。

    Tip

    生成器函数可以传参,有 arguments

总结

  • 生成器函数做一个了解就行,毕竟使用场景不多。