Iterator 概念
遍历器是一种接口,为各种不同的数据结构提供统一的访问机制。
作用:
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使数据结构成员能够按某种次序排列
- 主要供 for…of 消费
遍历过程:
- 创建一个指针对象
- 第一次调用指针对象的next方法,指针指向数据结构的第一个成员
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
- 不断调用指针对象的next方法,知道它指向数据结构的结束位置
每次调用next方法,返回一个包含value 和 done 两个属性的对象。
默认Iterator 接口
一种数据结构只要部署了 Iterator 接口,就是可遍历的。
Es6,默认的Iterator 接口部署在数据结构的Symbol.iterator 属性。
原生具备Iterator接口的数据结构:
- -Array
- -Map
- -Set
- -String
- -TypedArray
- -函数的arguments对象
- -NodeList对象
调用Iterator 接口的场合
以下场景会默认调用Iterator接口(即Symbol.iterator方法)
解构赋值
对数组和Set结构赋值时,会默认调用Symbole.iterator 方法
let set = new Set()set.add(1)set.add(2)set.add(3)let [x, y] = set
扩展运算符
扩展运算符也会调用默认的 Iterator 接口
let str = 'hello'[...str]
yield*
yield* 后面跟一个可遍历的结构,它会调用该结构的遍历器接口
let generator = function* () {yield 1;yield* [2, 3, 4];yield 5;}let generatorIterator = generator()console.log(generatorIterator.next())console.log(generatorIterator.next())console.log(generatorIterator.next())console.log(generatorIterator.next())console.log(generatorIterator.next())
其他场合
由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,都可以调用遍历器接口。
-for…of
-Array.from()
-Map(), Set(), WeakMap(), WeakSet()
-Promise.all()
-Promise.race()
字符串的Iterator接口
字符串是一个类似数组的对象,也原生具有Iterator 接口。
var someString = 'hi'var strIter = someString[Symbol.iterator]()console.log(strIter.next())console.log(strIter.next())console.log(strIter.next())
可以覆盖原生的Symbol.iterator 方法,达到修改遍历器行为的目的。
var objStr = new String('hello')console.log([...objStr])objStr[Symbol.iterator] = function() {return {next: function() {if (this._first) {this._first = falsereturn { value: 'bye', done: false }} else {return { done: true }}},_first: true}}console.log([...objStr]) // ['bye']console.log(objStr) // {'hello'}
Iterator 接口 与 Generator 函数
let myIterable = {* [Symbol.iterator]() {yield 1;yield 2;yield 3;yield 4;}}console.log([...myIterable])
遍历器对象的 return(), throw()
for…of 循环
数组
const arr = ['red', 'green', 'blue']for (let v of arr) {console.log(v)}// 遍历数组索引for (let key of Object.keys(arr)) {console.log(key)}for (let [key, value] of Ojbect.entries(arr)) {console.log(key, value)}
Set 和 Map 结构
Set 和 Map 结构也原声具有Iterator 接口
let engines = new Set(['Gecko', 'Trident', 'Webkit', 'webkit'])for (let e of engines) {console.log(e)}let es6 = new Map()es6.set('edition', 6)es6.set('committee', 'Tc39')for (let [key, value] of es6) {console.log(key + ' : ' + value)}
对象
for (let key of Object.keys(somObject)) {console.log(key+': ' + someObject[key])}
// 使用Generator 函数将对象重新包装一下function* entries(obj) {for (let key of Object.keys(obj)) {yield [key, Obj[key]]}}for (let [key, value] of entries(obj)) {console.log(key, '-> ', value)}
与其他遍历语法的比较
// for 循环for (let index = 0; index < myArray.length; index++) {console.log(myArray[index])}// forEach 方法myArray.forEach((value) => {console.log(value)})--forEach, 无法中途跳出forEach 循环, break和return 都不能奏效// for...in 循环for (let index in myArray) {console.log(myArray[index])}-----for...in缺点,不适用于遍历数组-数组的键名是数字-还会遍历手动添加的其他键,包括原型链上的键-某些情况下,for...in循环会以任意顺序遍历键名// for...of 循环优点:let iteArr = [10, 30, 60, 70]for (let n of iteArr) {if (n > 50) {break}console.log(n)}-有着同for...in 一样简洁语法,但是没有for...in那些缺点-不用于forEach,它可以与break、continue和return配合使用-提供了遍历所有数据结构的统一操作接口
