ES9 中 generator 函数改进,多个迭代器之间可以相互进行 “通信”

引言

在 ES6 中,我们引入了 generator 函数,它通过 yield 关键字使得函数执行可以暂停,并且随时可以恢复。ES9 中对 generator 函数做了一些改进,其中最重要的改进之一是实现了多个迭代器之间相互进行“通信”,这一改进非常有用,可以开发出更复杂和有趣的应用程序。

迭代器和生成器

在深入探讨 generator 函数的改进之前,我们需要先了解迭代器和生成器的基本概念。

在 JavaScript 中,迭代器主要有两个方法:next()return()。其中,next() 方法用于取出下一个元素,return() 方法用于结束迭代器的操作。

而生成器则是一种特殊的函数,其可以通过 yield 关键字使函数执行可以暂停,并且随时可以恢复。

ES9 中 generator 函数的改进

在 ES9 中,generator 函数的最重要的改进之一是实现了多个迭代器之间相互进行“通信”。

在 ES6 中,我们可以通过 yield 表达式将值从生成器迭代器传递到生成器函数。而在 ES9 中,我们可以通过 yield* 表达式将一个迭代器中的值传递给其他迭代器。

下面是一个简单的例子,我们可以借此了解这种改进的作用和实现方式:

-------- ------ -
  ----- --
  ----- --
  ----- --
-

-------- ------ -
  ----- --
  ------ ------
  ----- --
-

--- ---- - -- ------ -
  ---------------
-

在这个例子中,我们定义了两个生成器函数,分别是 foo()bar()。其中,foo() 函数返回一个简单的迭代器,它产生三个数字:1、2 和 3。而 bar() 函数则使用 yield* 将 foo() 函数返回的迭代器中的值传递给外层的迭代器。

在最后的 for 循环中,我们迭代了 bar() 函数返回的迭代器,输出了下面这些数字:

-
-
-
-
-

从上面的例子中可以看出:在 ES9 中,使用 yield* 实现多个迭代器之间的通信变得非常简单和方便。

深度分析

上面的例子过于简单,下面我们来看一个更复杂的例子,从中更深入地了解 yield* 的用法。

我们假设有一个学生名册,其中包含了学生的姓名、班级、考试科目和考试成绩。其中,每个学生可能在多个科目中都参加了考试。我们需要编写程序对学生进行分类统计,最终输出每个班级中每个学生每个科目的总分数、平均分数、最高分数和最低分数。

为了实现这个功能,我们需要实现三个函数:

  • group(students):将所有学生按班级进行分组。
  • score(students):将所有同班的同学按科目进行分组,并计算总分数、平均分数、最高分数和最低分数。
  • main(students):主函数,将上述两个函数组合起来,输出结果。

我们可以通过 ES9 中的 generator 函数实现这个功能:

-------- ---------------- -
  ----- ------ - --- ------
  --- ---- ------- -- --------- -
    --- ----- - --------------------------
    -- ------- -- ------ --------------------- --- ------------ -  
      ----- - -
        ---------------- --
        --------- --- -----
      -
      ------------------------- -------
    -
    -------------------------------- ---------
  -
  ------ ---------------------
-

-------- ---------------- -
  ----- ------ - --- ------
  --- ---- ------- -- --------- -
    --- ----- - --------------------------
    -- ------- -- ------ --------------------- --- ------------ -
      ----- - -
        ---------------- --
        --------- --- -----
      -
      ------------------------- -------
    -
    --- ------- - -----------------------------------------
    -- --------- -- ------ ------------------ --- ------------ -
      ------- - -
        ----------- --
        ------ --
        --------- ----------
        --------- --------
      --
      ---------------------------------------- - --------
    -
    ------------------ -- --------------
    ----------------
    ---------------- - -------------------------- ---------------
    ---------------- - -------------------------- ---------------
    --------------------- -- --------------
  -
  ------ ------------------------------ -- --
    ------ ------------
    --------- ---------------------------------------- -- --
      ----- -------------
      -------- ---------------
    ---
  ----
-

-------- -------------- -
  --- ---- ---------- -- ---------------- -
    -----------------------------------------------
    --------------------------------------
    ---------------------------------------------------
    --- ---- ------- -- --------------------------- -
      -------------------------------------------
      ----------------------------------
      ---------------------------------------------------------------------------------------------------------------------------------------------- - --------------------------
    -
  -
-

在上面的代码中,我们定义了三个 generator 函数分别为:group、score 和 main。在 group 函数中,我们首先按照班级进行分组,然后调用 yield* 将所有分组的结果迭代出来。在 score 函数中,我们按照班级和科目进行分组,并计算总分数、平均分数、最高分数和最低分数,然后调用 yield* 将结果迭代出来。最后,在 main 函数中,我们将上述两个函数组合起来,输出结果。

结论

在 ES9 中,实现多个迭代器之间相互进行“通信”变得非常简单和方便,我们只需要使用 yield* 表达式即可。借助这个特性,我们可以编写更复杂和有趣的应用程序,提高我们的编程效率和代码可读性。

在使用 yield* 表达式时,我们需要注意以下几点:

  • 如果迭代器 A 中的一个元素被 yield* 到另一个迭代器 B 中,那么当执行迭代器 B 的 return() 方法时,迭代器 A 的 return() 方法也会被自动调用。
  • 当使用 yield* 表达式时,最终的返回值是被 yield 的迭代器自己的 return() 方法的返回值。
  • 当我们使用 yield* 表达式时,我们可以通过在另一个迭代器中使用 yield 表达式来直接得到被 yield 的值。

在编写使用 yield* 表达式的代码时,我们需要更加细心,避免出现意外的错误。我们还需要注意所使用的 JavaScript 环境是否支持 ES9 中的 generator 函数特性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/67397ee3dee7df6752420aa0