前言
假如我有一个数组,我可以对它进行如下操作
let arr = ['foo', 'bar', 'baz']
// 遍历数组
for (let i of arr) {
console.log(i)
}
// 解构赋值
let [a, b, c] = arr
// 扩展操作符
let arr2 = [...arr]
那么为什么我们可以对数组进行这些高级操作呢?
因为数组是一个可迭代对象
,它的底层实现了迭代协议。
如果数组不是可迭代对象,那么我们可能就需要使用原始的for循环去实现上面的迭代操作,所以使用迭代器这种模式可以帮助我们更好的去组织代码,提升代码的可读性与可理解性
理解迭代协议
可迭代对象的关键在于对迭代协议的实现,迭代协议具体分为可迭代协议
和迭代器协议
可迭代协议
一个对象要成为可迭代对象,那么这个对象或者它的原型链上的某个对象必须实现了@@iterator方法,可以通过符号常量Symbol.iterator访问该属性
Symbol.iterator是一个无参的构造函数,返回一个符合迭代器协议
的对象
迭代器协议
一个对象只有在实现了具有以下语意的next()方法才能称为迭代器
- next()方法接收0个或者一个参数,必须返回一个包含以下两个属性的对象
- done:是否已经迭代完成
- value:迭代器产生的值,done为true时可以省略
实现自己的可迭代对象
可迭代对象的关键就是对于迭代协议的实现,实现对象的Symbol.iterator方法,调用Symbol.iterator方法返回一个迭代器,调用迭代器的next()方法对可迭代对象进行迭代,返回迭代的状态和值,下面是具体的代码实现
const iterableObj = {
[Symbol.iterator]() {
let limit = 5
let count = 0 // 通过闭包维护当前迭代器状态
return {
next() {
if (count < limit) {
return {
done: false,
value: count++,
}
} else {
return {
done: true,
}
}
},
}
},
}
// 调用可迭代对象的Symbol.iterator方法可以获得迭代器
let iterator = iterableObj[Symbol.iterator]()
// 调用迭代器的next()方法可以实现对可迭代对象的遍历
console.log(iterator.next()) // {done: false, value: 0}
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 3}
console.log(iterator.next()) // {done: false, value: 4}
console.log(iterator.next()) // {done: true}
// 使用for of遍历
for(let i of iterableObj) {
console.log(i) // 0, 1, 2, 3, 4
}
let [a, b, c] = iterableObj
console.log(a, b, c) // 0 1 2
let arr3 = [...iterableObj]
console.log(arr3) // [0, 1, 2, 3, 4]
总结
关于迭代器还有很多的语法细节和使用案列,本文只是让大家简单的了解了迭代器相关的概念,如果想要了解更多,推荐看下文末的相关参考文献
参考文献
- JavaScript高级程序设计
- 你不知道的 JavaScript(下)
- developer.mozilla.org/zh-CN/docs/…
- es6.ruanyifeng.com/#docs/itera…