简单理解遍历器Iterator
JS 中表示“集合”的数据结构有:Array、Object、Map、Set等。
需求:需要统一的接口机制,遍历不同表示“集合”的数据结构。
解决方案:遍历器(Iterator)就是这个接口,针对不同的数据结构完成都可遍历。
一般项目里其实不太用使用Iterator
,但是理解这个,可能是理解其他的基础,比如生成器。
Iterator 的遍历过程
遍历器对象本质上,就是一个指针对象(联想遍历各种结构的指针)。
(1)创建一个指针对象,指向当前数据结构的起始位置。,
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
怎么添加 Iterator接口
其实就是在数据结构中增加一个Symbol.iterator
属性,其是一个返回**Iterator(遍历器)**的函数。
遍历器的本质是个对象,有个next
方法(next的本质是函数,所以能调用),其是一个返回{value:xx,done:true/false}
的函数。
value
属性返回当前位置的成员,done
属性是一个布尔值,表示是否遍历结束,即是否还有必要再一次调用next方法。
用for of
遍历数据结构,就可以得到每次的value
。
var obj = { [Symbol.iterator]: function () { const keys = Object.keys(this) let p = 0 return { next: () => { const res = { value: this[keys[p]], done: keys.length < p + 1 } p++ return res } } }, a: 1, b: 2 } let it = obj[Symbol.iterator]() // 所谓的迭代器就是一个对象 console.log(it) // { next: [Function: next] } console.log(it.next()) // { value: 1, done: false } console.log(it.next()) // { value: 2, done: false } console.log(it.next()) // { value: undefined, done: true } for (let v of obj) { // 和上面一样,输出两次,1、2 console.log(v) }
也可使用生成器添加 Iterator接口
生成器执行的时候,直接返回遍历器实例。
var obj = { [Symbol.iterator]: function * () { yield 1 yield 2 }, a: 1, b: 2 } let it = obj[Symbol.iterator]() console.log(it) // Object [Generator] {} console.log(it.next()) // { value: 1, done: false } console.log(it.next()) // { value: 2, done: false } console.log(it.next()) // { value: undefined, done: true } for (let v of obj) { // 和上面一样,输出两次,1、2 console.log(v) }
天生有Iterator接口的数据结构
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
注意!!!对象没有内置Iterator接口,所以如果不是手动添加,不能使用for of
遍历
用数组举例看下:
var arr = [1, 2] let it = arr[Symbol.iterator]() console.log(it) // { next: [Function: next] } console.log(it.next()) // { value: 1, done: false } console.log(it.next()) // { value: 2, done: false } console.log(it.next()) // { value: undefined, done: true } for (let v of arr) { // 和上面一样,输出两次,1、2 console.log(v) }
遍历器的使用场景
- 解构
- 扩展运算符
- 由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口
- for...of
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
- Promise.all()
- Promise.race()
和其他遍历语法的比较
主要以遍历数组为例:
for
:比较繁琐forEach
:无法中途跳出forEach循环for in
:遍历数组的键名(索引),还有原型链上的键。当然一般遍历对象用的
for of
的优点:
- 有着同
for...in
一样的简洁语法,但输出的是是当前键对应的值。 - 可以
break、continue和return
配合使用。 - 提供了遍历所有数据结构的统一操作接口。
注意对象不能直接使用for of
,因为内置没有Iterator
。
引用
本文基本是总结这页,所以不明白的,可以多刷这页。