Iterator 可以看做一个拥有固定格式的对象,可供 ES6 新增的遍历 for of
和解构 ...
等消费,并按顺序依次产出结果,样例如下
// 除了以下俩个值外也可以额外返回更多的自定义属性
const IteratorResult = {
value: ..., // 每次迭代产出的真实值
done: ..., // true|false true代表迭代结束 与true相对应的value一般建议为undefined
}
const Iterator = {
// 必须 用于返回每次迭代的结果集
next() { return IteratorResult },
// 可选 提前结束迭代时做相应的资源清理操作并返回最后的结果集
return() {},
// 可选 抛出异常信息并返回最后的结果集
throw() {}
}
一个对象如果实现了 Iterable 接口则被称为 Iterabel 对象(简单来说就是对象上有一个 key 为 Symbol.iterator
的方法并且这个的返回值为 Iterator)
const Iterable = {
[Symbol.iterator]() {return Iterator}
}
let rand = Math.random()
// 会随机产生一串数字的Iterable对象
const iterable = {
// 必备!!! 这样才能使该对象 Iterable
[Symbol.iterator]() {return this},
// 依次去获取数据
next() {
if (rand > 0.5) {
rand = Math.random()
return {
value: rand,
done: false
}
} else {
return {
done: true
}
}
}
}
// 该对象可以用 for of 遍历
for (let value of iterable) {
console.log(value)
}
// 该对象可以步进的产生对数据的每一步累加结果
const stepAccumulator = {
[Symbol.iterator]() {
let sum = 0
let index = 0
const data = this.data.slice()
let done = false
return {
// 使迭代器(Iterator)本身可迭代(Iterable)
[Symbol.iterator]() { return this },
next() {
const value = sum += data[index]
index++
if (index <= data.length && !done) {
return {
value,
done: false
}
} else {
return {
done: true
}
}
},
return(v) {
console.log('abandoned')
done = true
return {
value: v,
done: true
}
},
throw(e) {
console.log('error')
done = true
return {
value: e,
done: true
}
}
}
},
data: []
}
// 设置数据
stepAccumulator.data = [1, 2, 3]
console.log(...stepAccumulator) // 1 3 6
// 1 3 'abandoned'
for (let v of stepAccumulator) {
console.log(v)
if (v > 1) break
}
const it = stepAccumulator[Symbol.iterator]()
it.next() // { value:1, done: false }
it.throw('!!!') // 'error' { vallue:'!!!', done: true }
it.next() // { done: true }
return()
和 throw()
都可以通过 Iterator 调用,并且调用后意味着迭代终止,之后便不能通过该迭代器获取到更多的值return()
来处理相关清理工作包括 String
Map
Set
Array
等
const str = 'abc'
const arr = [1, 2, 3]
const map = new Map()
map.set('a', 1)
map.set('b', 2)
for (let v of str) {
console.log(v) // 'a' 'b' 'c'
}
for (let v of arr) {
console.log(v) // 1 2 3
}
for (let v of map) {
console.log(v) // ['a', 1] ['b', 2]
}