Iterator
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
1 | var map = new Map([["name", "张三"], ["title", "Author"]]); |
Iterator接口
在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
1 | let arr = ['a', 'b', 'c']; |
构造具有Iterator接口的对象。
1 | class RangeIterator { |
上面的例子是指定对象本身就含有next函数,所以迭代器函数返回对象本身是可行的。如果要对一个Object实现迭代功能,则需要对Symbol.Iterator进行定义。
1 | function Obj(value){ |
上面代码首先在构造函数的原型链上部署Symbol.iterator方法,调用该方法会返回遍历器对象iterator,调用该对象的next方法,在返回一个值的同时,自动将内部指针移到下一个实例。
对于类似数组对象(存在数值键名和length属性),部署Iterator接口才会使用扩展运算符和for...of循环。
1 | var arrayLike = { |
调用Iterator场合
解构赋值
1 | let set = new Set().add('a').add('b').add('c'); |
扩展运算符
1 | // 例一 |
yield*
跟着一个可遍历的结构,会调用该结构的遍历器接口。与function*一起用。
1 | let generator = function* () { |
字符串的Iterator接口
1 | var someString = "hi"; |
Iterator与Generator函数
主要介绍放到下一章节。
1 | var myIterable = {}; |
遍历器对象的return(),throw()
return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句或continue语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。
1 | var str = new String("hello world"); |
for…of
一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。
数组
注意区分的是,for...of返回的是数组元素,for...in返回的是数组的键名。
1 | var arr = ['a', 'b', 'c', 'd']; |
另外,for...of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。
1 | var arr = [3, 5, 7]; |
Set & Map
1 | var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]); |
类似数组的对象
比如字符串,arguments都可以直接使用for...of进行遍历。而对于类似数组对象就要使用Array.from转为数组。
1 | let arrayLike = { length: 2, 0: 'a', 1: 'b' }; |
其他普通对象想要用for...of遍历,需要使用Object.keys()。否则只是赋值给iterator接口函数也无法输出。因为它不是一个类数组对象。
另一种方法是使用Generator函数将对象重新包装一下。
1 | var es6 = { |
遍历方法比较
Array.forEach
Array对象内置有forEach方法,但是不能中途跳出,break和return语句都无法工作。
for…in
循环遍历数组。
数组键名是数组,但是返回会是字符串"0"等等。
不止返回数字键名,还会返回原型链上的键。
循环顺序不稳定。
1 | var arrayLike = { |
总之,for...in是为遍历对象而设计的,不适合遍历数组。
for…of
1 | for (let value of myArray) { |
有着同for...in一样的简洁语法,但是没有for...in那些缺点。
不同用于forEach方法,它可以与break、continue和return配合使用。
提供了遍历所有数据结构的统一操作接口。