迭代器
迭代器模式
迭代器模式描述了一个方案,一些可以被迭代的结构实现了正式的interable接口并可以通过迭代器interator消费被称为可迭代结构,任何实现了interable接口的结构都能够被interator对象消费,interator对象是按需创建的一次性结构,每一个迭代器对象关联了一个可迭代对象,迭代器会暴露出其关联对象的api,迭代器不需要知道关联对象的具体结构,他只需要调用对应的api连续获取可迭代对象的值。
js中的迭代器
可迭代协议(interable接口)
上面说了实现了可迭代接口的结构称为可迭代结构,实现了可迭代协议(interable接口)要求能够支持迭代,并且能够实现生成实现了迭代器协议(interator接口)的能够,在ecmscript中这就要求我们暴露出一个属性用来生成对象,js中使用Symbol类型来标识这一属性[Symbol.interator],使用原生语言如for...of,数组的结构赋值,扩展操作符等迭代对象时会默认调用这一个属性来生成迭代器对象。
迭代器协议(interator接口)
迭代器协议是一个一次性对象,他通过调用迭代器api来获取关联对象的数值,在js中迭代器对象调用next()方法来获取可迭代结构的值,next()对象会获取到一个迭代结果对象其中包含了value和done属性,value属性获取的是当前关联的可迭代对象的信息,而done属性是一个布尔值,表示这个迭代器关联的对象是否迭代完毕
js中的一些迭代方法默认调用对象中的[Symbol.iterator]属性,这个属性一般是一个工厂函数,调用会生成一个迭代器对象,迭代器对象是一种独立的、一次性的对象,它的根本属性是包含了一个next()方法,在进行迭代时迭代器对象会调用next方法,这个方法会返回迭代结果对象,我们可以先实现一个简单的实现迭代器接口的例子:
class example {
[Symbol.iterator](){
return {
a:1,
next(){
if(this.a < 10){
return {
value:this.a++,
done:false,
}
}
else{
return{
value:undefined,
done:true
}
}
}
}
}
}
let examplea = new example()
for(let i of examplea){
console.log(i)
}
代码运行结果:
这里的for...of结构调用了example类中的构造器工厂函数[Symbol.iterator]生成了迭代器,迭代器调用了next()方法,当返回的对象中的done为ture之后循环结束
迭代器的独立性
我们可以通过默认的构造器工厂函数生成多个构造器,各个生成器之间并不会相互影响
let array = [1,3,6]
let itr = array[Symbol.iterator]();
let itr2 = array[Symbol.iterator]();
console.log(itr.next())
console.log(itr.next())
console.log(itr.next())
console.log(itr2.next())
运行结果
迭代器的一次性
当一个迭代器遍历完成之后再次调用构造器就只会返回固定的数值{value:undefined,done:true},之后再次调用这个迭代器的next()方法只会返回相同的数值。
迭代器与关联对象之间的关系
构造器关联的可迭代对象并非是快照式的,而是一个类似指针指向关联对象,当关联对象的机构改变之后迭代器也的迭代结果也会相应的改变。
let array = [1,3,6]
let itr = array[Symbol.iterator]();
console.log(itr.next())
console.log(itr.next())
console.log(itr.next())
array.push(19)
console.log(itr.next())
运行结果
提前退出迭代
我们可以提前将循环结束,通过在构造器对象中加入return()可以让迭代器提前中止循环
class example {
constructor(num){
this.num = num;
}
[Symbol.iterator](){
let a = 1, number = this.num
return {
next(){
if(a < number){
return {
value:a++,
done:false,
}
}
else{
return{
value:undefined,
done:true
}
}
},
return(){
console.log('有内鬼,终止交易')
return {
value:undefined,
done:false
}
}
}
}
}
let exampleA = new example(9);
for(let i of exampleA){
console.log(i)
if(i == 6){
break;
}
}
运行结果:
并不是所有的实现了迭代器接口的对象都可以中断迭代,只有实现了return()方法的对象可以中断迭代。
迭代器的使用
原生语言如for..of,解构赋值,扩展操作符,Array.from()等会在后台自动调用对象的默认迭代器的工厂函数
let exampleA = new example(10)
let arrayOne = [2,3,4,5,6,7]
arrayOne[Symbol.iterator] = ()=>{
return{
next(){
return{
value:'this is a test',
done:false
}
}
}
}
let arrayIntor = arrayOne[Symbol.iterator]()
let [a,b,c] = arrayOne
let arrayTwo = Array.from(exampleA)
console.log(...exampleA)
console.log(`a:${a},b:${b},c:${c}`)
console.log('arrayTwo',arrayTwo)
运行结果