ES6看完必会第十三章------ Iterator(遍历器)(可私信解惑,不会来捶我)
Iterator(遍历器)的概念
遍历器(Iterator)是一种接口,为了各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator的作用有三个:
- 一是为各种数据结构,提供一个统一的、简便的访问接口;
- 二是使得数据结构的成员能够按某种次序排列;
- 三是ES6创造了一种新的遍历命令for...of循环。
Iterator的遍历过程如下:
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
数据结构的默认Iterator接口
Iterator接口的目的,就是为所有数据结构提供了一种统一的访问机制,即for...of循环。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找Iterator接口。
一种数据结构只要部署了Iterator接口,我们就称这种数据结构是”可遍历的“(iterable)。
ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。for...of循环会自动遍历它们。
对于类似数组的对象(存在数值键名和length属性),部署Iterator接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的Iterator接口。
let iterable = {
0: 'a',
1: 'b',
length: 2,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
调用Iterator接口的场合
有一些场合会默认调用Iterator接口(即Symbol.iterator方法),除了for...of循环以外,还有几个别的场合会调用该接口。
(1)解构赋值
对数组和Set结构进行解构赋值时,会默认调用 Symbol.iterator 方法。
let [n1,n2,n3]=[1,3,"a"];
(2)扩展运算符
扩展运算符(...)也会调用默认的iterator接口。
var str = 'hello';
[...str] // ['h','e','l','l','o']
(3)yield*
yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
let generator = function* () {
yield "a";
yield 2;
yield 5;
};
(4)其他场合
由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。下面是一些例子:
- for...of
- Array.from()
- Map(), Set()(比如new Map([['a',1],['b',2]]))
遍历器对象的return()
遍历器对象除了具有next方法,还可以具有return方法。
return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句或continue语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。
function foo(file) {
return {
next() { // next方法
},
return() { // return方法
},
};
}
注意,return方法必须返回一个对象,这是Generator规格决定的。
数组遍历语法的比较
for循环
最原始的就是for循环
for(var i=0;i<10;i++){
console.log(i);
}
forEach
数组提供内置的forEach方法,缺点是无法中途跳出forEach循环,break命令或return命令都不能奏效。
myArray.forEach(function (value) {
console.log(value);
});
for...in
遍历的是key。
缺点:数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
for...in循环主要是为遍历对象而设计的,不适用于遍历数组。
for (let i of list) {
console.log( i );
}
for...of
遍历的是value。
for ...of 循环相比上面几种做法,有一些显著的优点。
- 有着同for...in一样的简洁语法,但是没有for...in那些缺点。
- 不同用于forEach方法,它可以与break、continue和return配合使用。
- 提供了遍历所有数据结构的统一操作接口。
for (var n of list ) {
if (n > 1000)
break;
console.log(n);
}