迭代器和生成器

迭代器和生成器


迭代器

背景知识

  1. 什么是迭代?

从一个数据集合中按照一定的顺序,不断取出数据的过程

  1. 迭代和遍历的区别?

迭代强调的是依次取数据,并不保证取多少,也不保证把所有的数据取完

遍历强调的是要把整个数据依次全部取出

  1. 迭代器

对迭代过程的封装,在不同的语言中有不同的表现形式,通常为对象

  1. 迭代模式

一种设计模式,用于统一迭代过程,并规范了迭代器规格:

  • 迭代器应该具有得到下一个数据的能力
  • 迭代器应该具有判断是否还有后续数据的能力

JS中的迭代器

JS规定,如果一个对象具有next方法,并且该方法返回一个对象,该对象的格式如下:

1
{value: 值, done: 是否迭代完成}

则认为该对象是一个迭代器

含义:

  • next方法:用于得到下一个数据
  • 返回的对象
    • value:下一个数据的值
    • done:boolean,是否迭代完成

可迭代协议

概念回顾

  • 迭代器(iterator):一个具有next方法的对象,next方法返回下一个数据并且能指示是否迭代完成
  • 迭代器创建函数(iterator creator):一个返回迭代器的函数

可迭代协议

ES6规定,如果一个对象具有知名符号属性Symbol.iterator,并且属性值是一个迭代器创建函数,则该对象是可迭代的(iterable)

for-of 循环

for-of 循环用于遍历可迭代对象,格式如下

1
2
3
4
5
//迭代完成后循环结束
for(const item in iterable){
//iterable:可迭代对象
//item:每次迭代得到的数据
}
1
2
3
4
5
6
7
8
9
10
const arr = [1, 2, 3, 4, 5];
const iterator = arr[Symbol.iterator]();
let result = iterator.next();
while (!result.done) {
console.log(result.value);
result = iterator.next();
}
for (const item of arr) {
console.log(item)
}

展开运算符与可迭代对象

展开运算符可以作用于可迭代对象,这样,就可以轻松的将可迭代对象转换为数组。

字符串时可迭代的。

生成器 (Generator)

1.什么是生成器?

生成器是一个通过构造函数Generator创建的对象,生成器既是一个迭代器,同时又是一个可迭代对象

2. 如何创建生成器?

生成器的创建,必须使用生成器函数(Generator Function)

3. 如何书写一个生成器函数呢?

1
2
3
4
//这是一个生成器函数,该函数一定返回一个生成器
function* 函数名(){

}
1
2
3
4
5
6
//创建一个生成器函数
function* test() {
yield 1;
yield 2;
}
const generator = test();

4. 生成器函数内部是如何执行的?

生成器函数内部是为了给生成器的每次迭代提供的数据

每次调用生成器的next方法,将导致生成器函数运行到下一个yield关键字位置

yield是一个关键字,该关键字只能在生成器函数内部使用,表达“产生”一个迭代数据。

5. 有哪些需要注意的细节?

1). 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function* test() {
yield 1;
yield 2;
return 10;
}
const generator = test();

运行结果:
generator.next()
{value: 1, done: false}
generator.next()
{value: 2, done: false}
generator.next()
{value: 10, done: true}

2). 调用生成器的next方法时,可以传递参数,传递的参数会交给yield表达式的返回值
3). 第一次调用next方法时,传参没有任何意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function* test() {
let n = yield 1;
console.log(n);
let n1 = yield 2 + n;
console.log(n1)
}
const generator = test();

运行结果:
generator.next()
{value: 1, done: false}
generator.next(33)
33
{value: 35, done: false}
generator.next(34)
34
{value: undefined, done: true}

4). 在生成器函数内部,可以调用其他生成器函数,但是要注意加上*号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

function* test1() {
yield 1;
yield 2;
}

function* test2() {
yield* test1()
yield "a";
yield "b";
}

const generator = test2();

运行结果:
generator.next()
{value: 1, done: false}
generator.next()
{value: 2, done: false}
generator.next()
{value: 'a', done: false}
generator.next()
{value: 'b', done: false}
generator.next()
{value: undefined, done: true}

6. 生成器的其他API

  • return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束
  • throw方法:调用该方法,可以在生成器中产生一个错误