Appearance
生成器 (Generator) 与迭代器 (Iterator)
迭代
迭代协议
规定了迭代与实现的逻辑
迭代器
具体的迭代实现逻辑
迭代对象
可被迭代的对象 - 实现了 [Symbol.iterator] 方法
迭代语句
for...in; 以原始插入的循序迭代对象的可枚举属性 for...of; 根据迭代对象的迭代器具体实现迭代对象数据
迭代器实现原理
[Symbol.iterator]
javascript
let arr = ["a", "b", "b"];
let obj = {
a: 1,
b: 2,
c: 3,
};
obj[Symbol.iterator] = function () {
// 迭代协议
let values = Object.values(obj);
let index = 0;
return {
next() {
if (index >= values.length) {
return {
done: true, // done 代表循环是否完成,true 已完成 false 未完成
};
}
return {
done: false,
value: values[index++],
};
},
};
};
for (const iterator of obj) {
console.log(iterator);
}
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
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
Generator 是一个特殊的函数,执行它会返回一个 Iterator 对象。 通过遍历迭代器, Generator
函数运行后会返回一个遍历器对象,而不是普通函数的返回值。
terators 模拟
迭代器有一个 next 方法,每次执行的时候会返回一个对象 对象里面有两个属性,一个是 value 表示返回的值,还有就是布尔值 done, 表示是否迭代完成
js
function buy(books) {
let i = 0;
return {
next(){
let done = i == books.length;
let value = !done ? books[i++] : undefined;
return {
value: value,
done: done
}
}
}
}
let iterators = buy(['js', 'html']);
var curr;
do {
curr = iterators.next();
console.log(curr);
} while (!curr.done);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Generator 函数
在形式上 Generator 是一个普通的函数,但是有两个特征。一是,function 命名与函数名之间有一个星号 二是,函数体内部使用 yield 语句,定义遍历器的每个成员,即不同的内部状态
Generator 语法
js
function* fn(){
yield 1;
yield 2;
yield 3;
}
let g = gen();
1
2
3
4
5
6
2
3
4
5
6
生成器用于创建迭代器
js
function* buy(books){
for(var i=0;i<books.length;i++){
yield books[i];
}
}
let buying = buy(['js','html']);
var curr;
do {
curr = buying.next();
console.log(curr);
} while (!curr.done);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
自执行 Generator 函数
co 函数,自动化 generator 函数调用器 Generator 是一个特殊的函数,执行它会返回一个 Iterator 对象。通过遍历迭代器,Generator 函数运行后悔返回遍历器对象,而不是函数的返回值。
javascript
function* fn() {
yield new Promise((resolve, reject) => {
setTimeout(() => {
console.log("a");
resolve(1);
}, 500);
});
yield new Promise((resolve, reject) => {
setTimeout(() => {
console.log("b");
resolve(2);
}, 500);
});
yield new Promise((resolve, reject) => {
setTimeout(() => {
console.log("c");
resolve(3);
}, 500);
});
}
co(fn);
function co(fn) {
let f = fn();
next();
function next(data) {
let res = f.next();
if (!res.done) {
// 上一个异步走完了,在执行下一个异步
res.value.then((info) => {
console.log(info, data);
// data 上一次的数据
next(info);
});
}
}
}
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
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