迭代器和生成器

迭代器和生成器是为了完成函数的中断效果而出现的。让原本只能一次性执行完的函数具备分段处理的功能。在本质上,这两者都属于函数的一种。

迭代器

官方介绍:在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。更具体地说,迭代器是通过使用 next() 方法实现 Iterator protocol 的任何一个对象,该方法返回具有两个属性的对象: value,这是序列中的 next 值;和 done ,如果已经迭代到序列中的最后一个值,则它为 true 。如果 value 和 done 一起存在,则它是迭代器的返回值。

简单的来说就是:迭代器本身就只是_具备闭包_和_对返回值有格式要求_的并且使用next()方法进行调用的一个函数而已。

让我们手撸一个了解一下。

 1//自定义迭代器
 2function makeRangeIterator(start = 0, end = Infinity, step = 1) {
 3    let nextIndex = start
 4    let iterationCount = 0
 5
 6    const rangeIterator = {
 7       next: function() {
 8           let result
 9           //判断是否具备继续执行的条件
10           if (nextIndex < end) {
11               result = { value: nextIndex, done: false }
12               nextIndex += step
13               iterationCount++
14               return result
15           }
16           return { value: iterationCount, done: true }
17       }
18    }
19    //不同于寻常了解的闭包,这里返回的是一个对象而非函数
20    return rangeIterator
21}
22
23//初始化按迭代器功能。
24let it = makeRangeIterator(1, 10, 2)
25
26//进行next的调用
27let result = it.next()
28//判断是否需要继续执行
29while (!result.done) {
30 console.log(result.value)
31 result = it.next()
32}
33
34console.log("Iterated over sequence of size: ", result.value)
35

以上方形式出现的函数,就是被我称为迭代器的东西。

生成器

但这种自定义的迭代器有一个比较麻烦的地方是:需要我们自己去维护内部的状态,去编写内部的逻辑。

所以,_生成器_出现了。

生成器的官方介绍:生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态。生成器函数使用 function*语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为 Generator 的迭代器。通过调用生成器的下一个方法消耗值时,Generator 函数将执行,直到遇到 yield 关键字。

生成器对迭代器进行了下一层的封装。生成器内置了迭代器的业务逻辑。并为我们提供了语法糖。

上方迭代器的案例以生成器的形式再完成一遍如下👇

 1function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
 2    console.log(1);
 3      console.log(2);
 4    yield "第一次停顿,执行打印1,2";
 5      console.log(3);
 6      console.log(4);
 7     yield"第二次停顿,执行打印3,4";
 8      console.log(5);
 9      console.log(6);
10     yield "第三次停顿,执行打印5,6";
11      console.log(7);
12}
13var a = makeRangeIterator(1,10,2)
14
15a.next() //打印1,2和{value: '第一次停顿,执行打印1,2', done: false}
16a.next() //打印3,4和{value: '第二次停顿,执行打印3,4', done: false}
17a.next() //打印5,6和{value: '第三次停顿,执行打印5,6', done: false}
18a.next() //{value: undefined, done: true}

我想这个例子很直观。每调用过一次 .next() 函数,就会在同一个上下文被标记为_yield_的地方停顿等待。

yield_是生成器函数的中断标记,当生成器函数运行到yield标记的地方时。必须使用_next();才可以继续执行,直到遇见到下一个_yield_或_函数结束_为止。

最后

这玩意在工作中有什么用?对于95%的开发来说,这玩意都没什么用。知道知道面试答的上来就好了。想碰到用它的场景都很难。

个人笔记记录 2021 ~ 2025