迭代器的应用
数据处理:汇总下面对象中的数字
let a = {
b: {
c: [
'1',
'2',
'3'
],
d: [
'4',
'5',
'6',
'7'
],
e: [
'8',
'9',
'10'
]
}
}
// 这里不能使用for...of,是由于Object的prototype上没有[Symbol.iterator]方法,故会报错
for (let o of a) {
console.log(o)
}
// Uncaught TypeError: authors is not iterable
如果想遍历该对象,一是可以改变数据格式
for (let key in a) {
let r = []
for (let k in a[key]) {
r = r.concat(a[key][k])
}
console.log(r)
}
// ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
二是通过自定义Iterator 接口,使其可遍历
a[Symbol.iterator] = function () {
let b = this.b
let keys = Reflect.ownKeys(b)
let values = []
return {
next () {
if (!values.length) {
if (keys.length) {
values = b[keys[0]]
keys.shift()
}
}
return {
done: !values.length,
value: values.shift()
}
}
}
}
// 定义了[Symbol.iterator]接口后,就可以被for...of迭代了
for (let o of a) {
console.log(o)
}
可迭代协议
如果让一个对象是可遍历的,就要遵守可迭代协议,该协议要求
1.对象要部署一个以 Symbol.iterator 为 key 的键
2. Symbol.iterator 的值就是一个要遵守迭代器协议的无参函数
迭代器协议
迭代器协议要求符合以下条件:
1.一个对象需包含一个无参函数 next
2.next 返回值也是一个对象,包含 done 和 value 属性。其中 done 表示遍历是否结束,value 返回当前遍历的值。
具备默认Iterator 接口的数据类型
ES6 的有些数据结构原生具备 Iterator 接口(比如数组),即不用任何处理,就可以被for…of循环遍历。原因在于,这些数据结构原生部署了Symbol.iterator属性:
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
Generator和Iterator
Generator 天然满足可迭代协议,利用 Generator 就不再需要显示的写迭代协议了(因为Generator包含next方法和包含 done、value 属性的返回对象)。
// 用generator改写上面的迭代器接口函数:
a[Symbol.iterator] = function * () {
let b = this.b
let keys = Reflect.ownKeys(b)
let values = []
while (1) {
if (!values.length) {
if (keys.length) {
values = b[keys[0]]
keys.shift()
yield values.shift()
} else {
return false
}
} else {
yield values.shift()
}
}
}