ES6之Iterator迭代器

1. 什么是迭代器

迭代器是统一的接口,它是一个对象,对象里面有next方法,每次调用这个方法就会输出数据结构的成员。第一次输出第一个成员,第二次输出第二个成员,以此类推。输出成员的形式为:{value:值,done:true/false}。注意:done中的true表明当前循环完成了,false表明当前循环没有完成。

2. 为什么要使用迭代器

  1. 在没有使用迭代器之前,我们可以使用for循环来打印数组中的元素。

缺点:a.理解方面比较差;b.for中i的这个变量不好管理。

  1. 在没有使用迭代器之前,我们可以使用forEach方法来打印数组中的元素。

缺点:不能跳出循环,在forEach中使用break或者continue会报错。因为forEach是从头循环到尾,中间是不能有中断的。

  1. 在没有使用迭代器之前,我们可以使用for in来打印数组中的元素。

缺点:a.理解方面比较差;b.会循环出来不是我们数组中的索引的属性。
什么是不是我们数组中的索引的属性,下面来举一个例子说明一下:

1
2
3
4
5
6
7
8
9
10
let names = ["xiaoming","xiaohong","xiaoli"];
names.age = 18;
for(var name in names){
console.log(names[name]);
}
// 控制台打印出来的内容如下:
// xiaoming
// xiaohong
// xiaoli
// 18

此时你会发现你本意只是想把names数组中的那三个值打印出来,但是却发现你添加的age中的值18被打印出来了,与我们预期所期望的不符合。

3. 自己写一个迭代器

根据迭代器的特性,自己手写了一个迭代器的例子,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let names = ["xiaoming","xiaohong","xiaoli"];
function createIterator(arr){
var index = 0;
return{
next(){
return index < arr.length ? {value: arr[index++],done: false} : {value: undefined,done: true};
}
}
}
let iterator = createIterator(names);
iterator.next(); // {value: "xiaoming", done: false}
iterator.next(); // {value: "xiaohong", done: false}
iterator.next(); // {value: "xiaoli", done: false}
iterator.next(); // {value: undefined, done: true}

// 注意:为什么调用第三次next()方法的时候,done打印出来还是为false,其原因是因为
// 当它循环完"xiaoli"完之后,不知道后面还有没有内容,因此done的值为false,直到
// 再一次调用next()方法的时候(即第四次调用next()方法),done的值才为true

4. 默认迭代器

4.1 数组迭代器(内置方法)

1
2
3
4
let names = ["xiaoming","xiaohong","xiaoli"];
console.log(names[Symbol.iterator]); // ƒ values() { [native code] } 注意: 它是一个原
// 生的函数,这个函数存储在数组的一个属性上面
console.log(names[Symbol.iterator]()); // Array Iterator {} 当names[Symbol.iterator] //这个原生的函数一执行,它就会生成迭代器

4.2 类数组迭代器(内置方法)

1
2
3
4
5
6
let argsIt;
function fn(a,b,c){
argsIt = arguments[Symbol.iterator]();
}
fn(1,2,3);
console.log(argsIt); // Array Iterator {}

4.3 字符串迭代器(内置方法)

1
2
let str = "daipi173";
console.log(str[Symbol.iterator]()); // StringIterator {}

4.4 对象是没有内置的迭代器的,但是我们可以给它创建一个自己的迭代器

首先我们先看一看对象有没有内置的迭代器,代码如下所示:

1
2
let obj = {};
console.log(obj[Symbol.iterator]); // undefined

此时你会发现打印出来的是undefined,再一次的证实了对象是没有内置的迭代器的,但是我们可以给它创建一个自己的迭代器,代码如下所示:

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
41
42
// 方法一:
let obj = {
a: 1,
b: "b",
[Symbol.iterator]() { // 注意:Symbol.iterator是不可枚举的,所以后面的keys.length的长度为2而不是3
let index = 0;
return {
next: ()=>{
let keys = Object.keys(this);
return index < keys.length ? {value: this[keys[index++]],done: false}
: {value: undefined,done: true};
}
}
}
};
let o = obj[Symbol.iterator]();
console.log(o.next()); // {value: 1, done: false}
console.log(o.next()); // {value: "b", done: false}
console.log(o.next()); // {value: undefined, done: true}


// 方法二:
let obj = {
a:1,
b:"b",
c:"d"
};
obj[Symbol.iterator] = function(){
let index = 0;
return {
next: ()=>{
let keys = Object.keys(this); // keys = ["a", "b", "c"]
return index < keys.length ? {value: this[keys[index++]],done: false}
: {value: undefined,done: true};
}
}
};
let o = obj[Symbol.iterator]();
console.log(o.next()); // {value: 1, done: false}
console.log(o.next()); // {value: "b", done: false}
console.log(o.next()); // {value: "d", done: false}
console.log(o.next()); // {value: undefined, done: true}

5. 迭代器使用场景

5.1 for of循环

for(let a of b){}
for of的应用场景更加的广泛了,只要b是一个迭代器,它就是可以用一个for of来进行一个循环。

for of是可以使用break的,它的底层是调用next()方法,语义化更强。for of会自动调用迭代器中的next()方法。如:

1
2
3
4
5
6
7
8
9
10
let names = ["xiaoming","xiaohong","xiaoli"];
for(var name of names){
console.log(111);
if(name === "xiaohong"){
break;
}
}

// 控制台打印出的内容如下:
// 打印出2个111

5.2 数组新增方法

a. keys() 索引
b. values() 值
c. entries() 把索引和值都打印出来

1
2
let names = ["xiaoming","xiaohong","xiaoli"];
console.log(names.keys()); // Array Iterator {}
1
2
let names = ["xiaoming","xiaohong","xiaoli"];
console.log(names.values()); // Array Iterator {}
1
2
let names = ["xiaoming","xiaohong","xiaoli"];
console.log(names.entries()); // Array Iterator {}

5.3 解构赋值

1
2
3
4
5
6
7
8
9
let names = ["xiaoming","xiaohong","xiaoli"];
for(let [index,name] of names.entries()){
console.log(name);
}

// 控制台打印出来的内容如下:
// xiaoming
// xiaohong
// xiaoli

5.4 …运算符(一般来说都是扩展运算符)

1
2
3
let names1 = ["xiaoming","xiaohong","xiaoli"];
let names2 = ["xiaodai",...names1];
console.log(names2); // ["xiaodai", "xiaoming", "xiaohong", "xiaoli"]