Symbol.iterator & 生成器函数
那该多好 Lv2

生成器、迭代器

给对象添加迭代器属性

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
let obj = {
a:1,
b:2,
c:3,
[Symbol.iterator]: function(){
var index = 0;
let map = new Map();
// 把当前对象转换为Map对象
for(var key in this){
map.set(key, this[key])
}
// map.keys() 键名
// map.values() 键值
// mao.entries() 键值对
return {
next(){
// 拿到每个键值对形成的数组
// console.log(map.entries()) => {"a" => 1, "b" => 2, "c" => 3}
var mapEntries = [...map.entries()];
// mapEntries = [["a", 1],["b", 2],["c", 3]]
if(index < map.size){
// 只要当前位置比对象的长度小 就返回打散后的map对象的当前下标的值和值为false
// done 代表是否迭代完成
return {
value:mapEntries[index++],
done:false
}
}
// 否则返回的值为 undefined done为true
return { value:undefined, done:true }
}
}
}
}

生成器函数

每次调用next函数时,只会执行到下一个yield,之后的代码不会执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function* test(){
let value1 = yield 1;
console.log(value1); // 'two'
let value2 = yield 2;
console.log(value2); // 'three'
let value3 = yield 3;
console.log(value3); // 'four'
let value4 = yield 4;
console.log(value4); // undefined
}
var iter = test();
// 第一次调用传值不会被接收,第二次传值时会传递给第一个yield位置的变量 第三次传值 -> 第二个yield 以此类推
console.log(iter.next('one')); // {value: 1, done: false}
console.log(iter.next('two')); // {value: 2, done: false}
console.log(iter.next('three')); // {value: 3, done: false}
console.log(iter.next('four')); // {value: 4, done: false}
console.log(iter.next()); // {value: undefined, done: true}

使用生成器函数编写迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var obj = {
a:1,
b:2,
c:3,
[Symbol.iterator]: function* () {
var index = 0;
let map = new Map();
for(var key in this){
map.set(key, this[key])
}
var mapEntries = [...map.entries()];
// 循环生成yield
while(index < mapEntries.length){
yield mapEntries[index++];
}
}
}
// for of 底层相当于调用了 obj[Symbol.iterator].next().value
for (var i of obj) {
console.log(i); // ["a", 1] ["b", 2] ["c", 3] undefined
}
 评论