迭代器和生成器
迭代器和生成器是为了完成函数的中断效果而出现的。让原本只能一次性执行完的函数具备分段处理的功能。在本质上,这两者都属于函数的一种。
迭代器
官方介绍:在 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%的开发来说,这玩意都没什么用。知道知道面试答的上来就好了。想碰到用它的场景都很难。