请解释 JavaScript 中的迭代器 (Iterator) 和生成器 (Generator) 的概念和作用。

推荐答案

迭代器 (Iterator)

迭代器是一种对象,它允许你以某种方式遍历一个集合(例如数组、对象、Map、Set等)。它遵循特定的协议,主要包含一个 next() 方法。每次调用 next() 方法都会返回一个包含 valuedone 属性的对象。value 代表当前迭代的值,done 是一个布尔值,表示迭代是否完成。当 donetrue 时,表示迭代已经结束,不再有新的值。

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

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

生成器 (Generator)

生成器是一种特殊的函数,使用 function* 语法声明。生成器函数执行时不会立即运行,而是返回一个迭代器对象。生成器函数内部可以使用 yield 关键字来暂停执行,并返回一个值。每次调用迭代器的 next() 方法时,生成器函数会从上次 yield 处恢复执行,直到再次遇到 yield 或者函数结束。生成器可以创建无限序列,以及处理异步操作。

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

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

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


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

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

本题详细解读

迭代器 (Iterator) 详解

迭代器协议

迭代器协议定义了如何生成一个序列的值。它是一个对象,需要实现一个 next() 方法。这个 next() 方法返回的对象必须包含两个属性:

  • value: 迭代的当前值。
  • done: 一个布尔值,表示迭代是否完成。当为 true 时,表明没有更多值可以迭代了。

可迭代对象 (Iterable)

一个对象如果拥有一个名为 [Symbol.iterator] 的方法,并且这个方法返回一个符合迭代器协议的对象,那么它就是一个可迭代对象。JavaScript 中一些内置的数据结构,例如 ArrayMapSetString 都是可迭代对象。

使用场景

  • for...of 循环: for...of 循环可以直接遍历可迭代对象。
  • 展开语法 (...): 可以将可迭代对象展开为数组或函数参数。
  • 解构赋值: 可以使用解构语法从可迭代对象中提取值。
  • 自定义迭代: 当你需要自定义数据结构的遍历方式时,可以实现自定义的迭代器。

生成器 (Generator) 详解

生成器函数

生成器函数使用 function* 语法定义,它并非立即执行,而是返回一个生成器对象。

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

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

yield 关键字

yield 关键字用于暂停生成器函数的执行,并返回一个值。每次调用生成器对象的 next() 方法时,生成器函数会从上次 yield 语句处恢复执行,直到遇到下一个 yield 或者函数结束。

yield* 关键字

yield* 关键字可以委托另一个生成器或可迭代对象。

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

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

使用场景

  • 生成无限序列: 由于生成器函数可以暂停和恢复执行,因此可以用于生成无限序列的值。
  • 处理异步操作: 可以结合 async/await 来处理异步操作,使得异步代码看起来更像是同步代码。
  • 状态机: 可以实现状态机,根据不同的状态生成不同的值。
  • 惰性求值: 生成器只在需要的时候才计算值,可以节省资源。

生成器与迭代器的关系

生成器函数返回一个迭代器,因此生成器天然就是一个迭代器。 它使用 yield 提供 value ,并且通过内部逻辑控制 done 属性。 生成器让开发者更容易定义迭代行为,无需手动创建迭代器。

纠错
反馈