【笔记】JS的迭代器和生成器

前言

JS的迭代器和生成器学习笔记

迭代器

定义迭代器对象

  • 一个对象实现了next方法,并且next方法返回值是一个具有done属性和value属性的对象,则这个对象就是一个迭代器对象

done:当前游标所指的元素是否是最后一个元素

true:是最后一个元素
false:不是最后一个元素

value:当前游标所指的元素值,如果是最后一个值通常定义为undefined

1
2
3
4
5
const iterator = {
next: function () {
return { value: "value", done: false };
}
}
  • 在迭代器对象中实现return方法来立即终止迭代器
1
2
3
4
5
6
7
8
const iterator = {
next: function () {
return { value: "value", done: false };
}
return: function () {
return { value: undefined, done: true };
}
}

对象定义为可迭代对象

  • 如果对象中定义类实例方法[Symbol.iterator],则这个对象就是可迭代对象
  • [Symbol.iterator]方法必须返回一个迭代器才能将普通对象转换为可迭代对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const obj = {
valueList: [],
index: 0,
[Symbol.iterator]: function () {
return {
next: () => {
if (this.index < this.valueList.length) {
return { value: this.valueList[this.index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
}

可迭代对象遍历数据

1
2
3
for (let item of obj) {
console.log(item);
}

可迭代对象通过迭代器手动遍历数据

1
2
3
4
5
6
let iterator = obj[Symbol.iterator]();
let current = iterator.next();
while (!current.done) {
console.log(current.value);
current = iterator.next();
}

JS内置可迭代对象

  • Array数组
1
for (const item of [1, 2, 3]) {}
  • Set集合
1
for (const item of new Set([1, 2, 3])) {}
  • Arguments参数列表
1
2
3
function fn() {
for (const item of arguments) {}
}

可迭代对象可以使用的JS语法

for…of遍历

1
for (const item of [1, 2, 3]) {}

展开语法

1
const arr = [...[1, 2, 3]]

解构赋值

1
const [a, b, c] = [1, 2, 3]

生成器语法

1
2
3
function* fn() {
yield* [1, 2, 3]
}

可迭代对象可以作为参数传递的函数

部分构造方法

创建Map映射对象
1
const map = new Map([...[1, 2, 3]]);
创建WeakMap映射对象
1
const weakMap = new WeakMap([...[1, 2, 3]]);
创建Set集合对象
1
const set = new Set([...[1, 2, 3]]);
创建WeakSet集合对象
1
const weakSet = new WeakSet([...[1, 2, 3]]);

部分Promise类方法

Promise.all()
1
2
3
4
Promise.all([
new Promise((resolve, reject) => {resolve()}),
new Promise((resolve, reject) => {resolve()}),
])
Promise.rase()
1
2
3
4
Promise.race([
new Promise((resolve, reject) => {resolve()}),
new Promise((resolve, reject) => {resolve()}),
])

部分Array类方法

Array.from()
1
const arr = Array.from([1, 2, 3]);

生成器

  • 生成器是ES6新增的一种函数控制函数使用的方案,它可以更加灵活地控制函数暂停执行继续执行

定义生成器函数

  • 通过function*关键字定义生成器函数
1
function* fn() {}

yield关键字

  • 生成器函数中使用yield关键字定义函数执行的暂停位置
1
2
3
4
5
6
function* fn() {
console.log(1);
console.log(2);
yield;
console.log(3);
}

return关键字

  • 生成器函数中使用return关键字终止函数
1
2
3
4
5
function* fn() {
console.log(1);
console.log(2);
return;
}

调用生成器函数返回生成器对象

  • 生成器函数在调用后会返回一个生成器对象,而不是直接执行生成器函数体内的代码
1
2
3
function* fn() {}

const generator = fn();

next方法

  • 当第一次调用next方法时,从头执行代码
  • 当第二次及之后调用next方法时,继续执行代码
  • 每次执行到yield关键字时会暂停执行,并立即返回一个结果对象,结果对象中包含value属性和done属性
  • 当执行到return关键字时,结果对象的done属性值立即变为true,且不会再执行后续代码
  • 当没遇到return关键字并执行完所有生成器定义的代码后(相当于return undefined),结果对象的done属性值变为true
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* fn() {
console.log(1);
console.log(2);
yield;
console.log(3);
yield;
console.log(4);
return;
console.log(5);
}

// 调用生成器函数返回生成器对象
const generator = fn();

// 从函数起始位置执行到yield关键字处暂停执行
console.log(generator.next());

// 继续执行到下一次yield关键字处暂停执行
console.log(generator.next());

// 继续执行到生成器函数结束或遇到return关键字
console.log(generator.next());

// 函数执行已完成,没有代码会被执行,即便是return关键字之后定义了其他代码
console.log(generator.next());
1
2
3
4
5
6
7
8
1
2
{ value: undefined, done: false }
3
{ value: undefined, done: false }
4
{ value: undefined, done: true }
{ value: undefined, done: true }

yield返回参数

1
2
3
4
5
6
7
8
function* fn() {
yield "value";
}

const generator = fn();

console.log(generator.next()); // { value: "value", done: false }
console.log(generator.next()); // { value: undefined, done: true }

return返回参数

1
2
3
4
5
6
7
8
function* fn() {
return "value";
}

const generator = fn();

console.log(generator.next()); // { value: "value", done: true }
console.log(generator.next()); // { value: undefined, done: true }

生成器对象调用next方法时传递参数

第一次调用next方法时

1
2
3
4
5
6
7
8
9
function* fn() {
const key = yield;
console.log(key); // "value"
}

const generator = fn("value");

generator.next();
generator.next();

第二次及之后调用next方法时

1
2
3
4
5
6
7
8
9
10
11
function* fn() {
yield;
const key = yield;
console.log(key); // "value"
}

const generator = fn();

generator.next();
generator.next("value");
generator.next();

yield返回参数与生成器对象调用next方法时传递参数

第一次调用next方法时

1
2
3
4
5
6
7
8
9
function* fn() {
const key = yield "value2";
console.log(key); // "value1"
}

const generator = fn("value1");

console.log(generator.next()); // { value: "value2", done: false }
console.log(generator.next()); // { value: undefined, done: true }

第二次及之后调用next方法时

1
2
3
4
5
6
7
8
9
10
11
function* fn() {
yield;
const key = yield "value2";
console.log(key); // "value1"
}

const generator = fn();

console.log(generator.next()); // { value: undefined, done: false }
console.log(generator.next()); // { value: "value2", done: false }
console.log(generator.next()); // { value: undefined, done: true }

return方法

  • 当调用return方法时,并立即返回一个结果对象,结果对象的done属性值立即变为true,且不会再执行后续代码
1
2
3
4
5
6
7
function* fn() {
yield;
}

const generator = fn();

console.log(generator.return()); // { value: undefined, done: true }

return方法传递参数

1
2
3
4
5
6
7
function* fn() {
yield;
}

const generator = fn();

console.log(generator.return("value")); // { value: "value", done: true }

throw方法

  • 当调用throw方法时,会抛出一个异常
1
2
3
4
5
6
7
8
9
10
11
function* fn() {
try {
yield;
} catch (e) {
console.log(e); // "error"
}
}

const generator = fn();

console.log(generator.throw(new Error("error")));

生成器的实质

  • 生成器的实质是一个特殊的迭代器,可以通过定义迭代器对象实现生成器的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function* fn() {
console.log(1);
console.log(2);
yield "value1";
console.log(3);
return "value2";
}

const generator = fn();

const result1 = generator.next();
console.log(result1);

const result2 = generator.next();
console.log(result2);

const result3 = generator.next();
console.log(result3);
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const obj = {
fnList: [
function () {
console.log(1);
console.log(2);
},
function () {
console.log(3);
},
],
index: 0,
[Symbol.iterator]: function () {
return {
next: () => {
if (this.index < this.fnList.length - 1) {
this.fnList[this.index]();
this.index += 1;
return { value: "value1", done: false };
} else if (this.index === this.fnList.length - 1) {
this.fnList[this.index]();
this.index += 1;
return { value: "value2", done: true };
} else {
return { value: undefined, done: true };
}
}
};
}
}

let iterator = obj[Symbol.iterator]();

const result1 = iterator.next();
console.log(result1);

const result2 = iterator.next();
console.log(result2);

const result3 = iterator.next();
console.log(result3);

通过yield*迭代可迭代对象

  • yield*关键字可以迭代可迭代对象
1
2
3
4
5
arr = [1, 2, 3];

for (let i of arr) {
console.log(i);
}
1
2
3
4
5
6
7
8
9
10
11
arr = [1, 2, 3];

function* fn(arr) {
yield* arr;
}

const generator = fn(arr);

console.log(generator.next().value);
console.log(generator.next().value);
console.log(generator.next().value);

通过yield*定义对象的[Symbol.iterator]方法

  • *[Symbol.iterator]就是将[Symbol.iterator]方法定义为生成器函数
1
2
3
4
5
6
const obj = {
valueList: [],
*[Symbol.iterator]: function () {
yield* this.valueList;
}
}

完成