Iterator (迭代器)是一种接口机制,为各种不同的数据结构提供统一的访问机制;主要为 for of 消费;将不支持遍历的数据结构变成“可遍历”。
迭代协议有两个条件:可迭代协议(指对象上有 Symbol.iterator 属性);迭代器协议(指当前必须返回迭代器对象,对象上必须有一个 next 方法,next 方法又返回一个对象,含有 value 和 done )
js
function makeIterator(arr) {
let nextIndex = 0
return {
next() {
return nextIndex < arr.length ? {
value: arr[nextIndex++],
done: false
} : {
value: undefined,
done: true
}
}
}
}
let it = makeIterator([1, 2])
console.log(it.next()) // {value: 1, done: false}
console.log(it.next()) // {value: 1, done: false}
console.log(it.next()) // {value: undefined, done: true}
// 将不支持遍历的数据结构变成“可遍历”
let course = {
allCourse: {
frontend: ['ES', 'Vue', 'React'],
backend: ['Java', 'Spring']
}
}
// 下面代码执行报错:Uncaught TypeError: course is not iterable
// In order to be iterable, non-array objects must have a [Symbol.iterator]() methds.
// for(let c of course) {
// console.log(c)
// }
let arr1 = [1, 2]
let it2 = arr1[Symbol.iterator]()
console.log(it2.next()) // {value: 1, done: false}
console.log(it2.next()) // {value: 2, done: false}
let m = new Map() // 可迭代
m.set('name', 'lisi')
m.set('age', 18)
let it3 = m[Symbol.iterator]()
console.log(it3.next()) // {value: ['name', 'lisi'], done: false}
console.log(it3.next()) // {value: ['age', 18], done: false}
原生具备的 Iterator 接口的数据结构: Array、Map、Set、String、TypedArray、普通函数 arguments 对象、 NodeList 对象
js
// 可迭代协议: Symbol.iterator
// 迭代器协议: return { next(){ return {value, done}}}
// 将不支持遍历的数据结构变成“可遍历” 使用 iterator
let course = {
allCourse: {
frontend: ['ES', 'Vue', 'React'],
backend: ['Java', 'Spring']
}
}
course[Symbol.iterator] = function() {
let allCourse = this.allCourse
let keys = Reflect.ownKeys(allCourse)
let values = []
console.log(1)
return {
next() {
if(!values.length) {
if(keys.length) {
values = allCourse[keys[0]]
keys.shift()
console.log(2)
}
}
return {
done: !values.length,
value: values.shift() // 注意这里 key 的顺序
}
}
}
}
for(let c of course) {
console.log(c)
}
// 使用 generator
course[Symbol.iterator] = function* () {
let allCourse = this.allCourse
let keys = Reflect.ownKeys(allCourse)
let values = []
while(1) {
if(!values.length) {
if(keys.length) {
values = allCourse[keys[0]]
keys.shift()
console.log(2)
yield values.shift()
} else {
return false
}
} else {
yield values.shift()
}
}
}
for(let c of course) {
console.log(c)
}