ES6中的遍历器接口Iterator

初读阮一峰老师的这本书,简直如发现了新世界一般.原来ES6的语法是如此的清奇.

随着ES6, ES7, 到今年七月份的ES8. 我们会发现,javascript这门最初被定义在客户端的’玩具语言’已经变得越发的强壮和标准,这也是我们作为前端ers 所希望看到的,毕竟,这涉及到以后的饭碗呢哈哈.

阮一峰老师的文笔还是不错的,但是随着后面的阅读,会发现有一些后面的知识,被直接不明就里的拿到前面来用了,这就导致我这个新手小白就有点懵逼了.

比如说: 箭头函数,当然,这个比较好理解,有固定的语法

但是,阮老师一直有提到的iterator接口,到底是个啥? 估计初学ES6的新手小白自然会有着和我一样的困惑.

那么,下面就综合我的搜索和总结,对iterator接口的相关知识,做一个分享,也算是对自己所学的一个总结

iterator接口是什么

不知大家碰到此问题的时候是不是和我一样马上选择了百度(毕竟英语不够好,不能随随便便Google一下啊),泪奔~

百度上面会告诉你, Java的iterator很好用巴拉巴拉

那么,在javascript中,iterator接口到底是个神马东西呢?

iterator, 其实就是一个迭代器,或者说,是一个迭代器

在es6中,能表示“集合”概念的数据类型大致有四种:Array,Object,Map,Set

既然是集合,那遍历便是一种基本需求。而Iterator就是为了提供一种统一的接口机制。任何的数据结构,只要部署了Iterator接口,便可以使用类似的方式完成遍历操作。

当然,Iterator还有2个作用,它使数据结构的成员按某种次序排列,其次,es6有一种新的遍历方式,前面也说过,for…of,而Iterator的主要作用,就是支持此操作。

Iteartor的遍历过程是这样的

创建一个指向数据结构起始位置的指针。(起始位置不是第一个成员的位置,起始位置使一个单独的标志位。)

当调用next()方法,指针就向后移动一个位置,并返回当前位置上的成员,直到指针指向数据结构的结束位置为止。

第二步中,js语言返回的的成员信息是两个,value和done,value不用介绍,done是一个表示遍历是否结束的布尔值。

部署接口

上面我们说到的部署接口,那js怎么部署接口呢。其实我们之前已经说到过,在Symbol一节中,介绍了很多es6内置的Symbol值,这些就是接口。

es6中有三类结构生来就具有Iterator接口:数组、类数组对象、Map和Set结构。

当然,如果你和我一样,现在看到第八章的话,暂时是没有学到Map和Set结构的,这个看下就好

1
2
3
4
5
6
7
8
var arr = [1,2,3,4];
let iterator = arr[Symbol.iterator]();

console.log(iterator.next()); //{ value: 1, done: false }
console.log(iterator.next()); //{ value: 2, done: false }
console.log(iterator.next()); //{ value: 3, done: false }
console.log(iterator.next()); //{ value: 4, done: false }
console.log(iterator.next()); //{ value: undefined, done: true }

数组,Map等结构中的成员都是有顺序的,即都是线性的结构,而对象,各成员并没有一个确定的顺序,所以遍历时先遍历谁后遍历谁并不确定。所以,给一个对象部署iterator接口,其实就是对该对象做一种线性转换。

如果有需要,可以手动给对象部署iterator接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};

可以看到,Symbol.iterator会返回一个对象,这就是一个遍历器对象,而作为遍历器对象,其必须具备的特征就是必须具备next()方法。

至于可以使用Array.from转换成数组的类数组对象,部署iterator有一种很简单的方法,即直接使用数组的[Symbol.iterator]接口。

1
fakeArray.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

用Generator函数来实现Symbol.iterator接口,事半功倍。

这也是看到第八章我要出来百度的原因,因为影响到了我正常的往下阅读了

1
2
3
4
5
6
7
8
var yieldIterator = {};
yieldIterator[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};

[...yieldIterator] // [1, 2, 3]

注意,yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

  其次,其它调用到遍历器的操作还有解构赋值、扩展操作符、其它任何接受数组作为参数的场合,如:

for…of
Array.from()
Map(), Set(), WeakMap(), WeakSet()(比如)
Promise.all()
Promise.race()

一旦当你给你的结构部署了iterator接口,那么恭喜你,你可以使用for…of来遍历你的结构了!

遍历器对象除了必须布置next方法以外,还有2个可选方法。return()和throw()。当一个解构在遍历的时候异常提前退出(比如break,continue或者出错)的时候,就会调用return方法,其次,return方法必须返回一个对象。

至于throw方法,则是用于抛出错误,Generator.prototype.throw

for of循环有很多优点,比如不像for…in一样只遍历键名(甚至包括原型链上的键),而且不像foreach不能跳出循环。并且for…of为各种数据结构提供了一个统一的遍历方法。所以,尽量使用它吧~

文章目录
  1. 1. iterator接口是什么
    1. 1.1. Iteartor的遍历过程是这样的
  2. 2. 部署接口
|