持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
迭代器
迭代器实现对不同结构的容器对象的遍历,开发者不用关心容器对象的内存分配的实现细节。简单来说,在使用迭代器的时候,可以在不用关心被遍历的对象是怎么实现的情况下遍历对象。
JavaScript的迭代器
JavaScript内的迭代器都应该遵循迭代协议。
迭代协议
迭代协议作为ECMA2015的补充规范,不是新语法,用来约束行为。迭代协议分为可迭代协议和迭代器协议。
可迭代协议
可迭代协议协议允许JavaScript对象定义或者定制它们的迭代行为。
要成为可迭代对象,这个对象必须实现@@iterator方法。String、Array、Map、Set这些内置对象的原型对象都实现了@@iterator方法,有默认的迭代行为。其他的对象可以通过实现@@iterator方法定制迭代行为,那这个对象或者说原型链上的某个对象会有一个键为@@iterator的属性,可以通过Symbol.iterator访问这个属性。
值得一提的是ES6之后新增的for-of。当使用for-of迭代一个对象时,会先调用它的@@iterator方法,通过这个方法返回的迭代器来获得要迭代的值。
迭代器协议
定义了一个对象要成为迭代器需要的next()方法。
next()必须返回一个对象,对象要有两个属性:done和value,如果没有返回对象,会抛出TypeError错误。
done:如果迭代器可以生成序列中的下一个值,为false,如果迭代完毕,为true。当done为true,value可以省略,但是如果value存在,value是迭代结束后的默认返回值。
value:迭代器返回的任何JavaScript值,done为true的时候可省略。
// 举个栗子:自定义iterator
let obj = {
[Symbol.iterator]:()=>({
text: 'object',
next(){
if(this.text==='test'){
return {
done: true
}
} else {
return{
value: this.text = 'test',
done: false
}
}
}
})
}
for(let i of obj){
console.log(i)
}
// 输出是test
在迭代器的角度看循环
do-while
do{
语句1
}while(语句2)
先执行语句1,再执行语句2,如果语句2返回true,继续执行语句1,如果语句2返回false,停止循环。
语句2返回true/false,可以理解next()返回done的值,语句1的执行结果是next()的value。
while
while(语句1){
语句2
}
先执行语句1,如果返回true,继续执行语句1,如果语句1返回false,停止循环。
语句1返回的true/false,可以理解next()返回done的值,语句2的执行结果是next()的value。
for
for(语句1;语句2;语句3) {
语句4
}
先执行语句1,再执行语句2,如果返回true,执行语句4,然后执行语句3,拿到语句3的结果后,再执行语句2,当语句2返回false时,停止循环。
可以理解在语句2返回的true/false是next()返回的done值,语句4执行的结果是next()的value。
for-in
for(x in obj) {
语句
}
JavaScript特有循环对象的可枚举属性,体现出对象属性的enumerable。
可以理解属性是否是可枚举属性是next()的done值,读取到的属性值为next()的value。
for-of
与for-in类似,前文已经介绍过。
for-await-of
与for-of类似,不同的是,next()的value是一个异步函数。
结语
JavaScript迭代器也有一些讨论,比如关于迭代器和生成器的讨论。限于篇幅,先写一些比较清晰的结论。欢迎留言讨论。