迭代器

迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象。迭代器API使用next()方法在可迭代对象中遍历数据。next()方法返回的迭代器对象IteratirResult包含两个属性:donevaluedone是一个布尔值,表示是否还可以再次调用next()取得在一个值。

//可迭代对象
let arr = ['foo','bar']

//迭代器工厂函数
console.log(arr[Symbol.iterator]);

//迭代器
let iterator = arr[Symbol.iterator]();
console.log(iterator);

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

每个迭代器都表示对可迭代对象的一次性有序遍历。不同迭代器的实例相互之间没有联系,独立地遍历可迭代对象。

let iter1=arr[Symbol.iterator]();
let iter2=arr[Symbol.iterator]();

console.log(iter1.next());
console.log(iter2.next());
console.log(iter1.next());
console.log(iter2.next());

迭代器并不与可迭代对象某个时刻的快照绑定,而仅仅是使用游标来记录遍历可迭代对象的历程。如果可迭代对象在迭代期间被修改了,那么迭代器也会反映相应的变化。

//可迭代对象
let arr = ['foo','bar']

//迭代器工厂函数
console.log(arr[Symbol.iterator]);

//迭代器
let iterator = arr[Symbol.iterator]();
console.log(iterator);

console.log(iterator.next());

arr.splice(1,0,'baz');

console.log(iterator.next());
console.log(iterator.next());

自定义迭代器

此例中的Counter类只能被迭代一定的次数。

class Counter{
    //Counter实例应该迭代limit次
    constructor(limit) {
        this.count=1;
        this.limit=limit;
    }

    next(){
        if(this.count<=this.limit){
            return {done:false,value:this.count++};
        }else{
            return {done:true,value:undefined};
        }
    }
    [Symbol.iterator](){
        return this;
    }
}
let counter = new Counter(3);
for(let i of counter){
    console.log(i);
}

这个类实现了Iterator接口,但不理想。它的每个实例只能被迭代一次。

for(let i of counter){
    console.log(i);
}
//1
//2
//3
for(let i of counter){
    console.log(i);
}
//(nothing logged)

可以将计数器变量放到闭包里,然后通过闭包返回迭代器。

class Counter{
    //Counter实例应该迭代limit次
    constructor(limit) {
        this.limit=limit;
    }
    [Symbol.iterator](){
        let count =1;
        let limit = this.limit;
        return {
            next(){
                if(count<=limit){
                    return {done:false,value:count++};
                }else{
                    return {done:true,value:undefined};
                }
            }
        };
    }
}
let counter = new Counter(3);
for(let i of counter){
    console.log(i);
}
//每创建一个新迭代器就对应一个新计数器。
for(let i of counter){
    console.log(i);
}

每个迭代器也实现了Iterable接口,所以它们可以用在任何期待可迭代对象的地方,比如for-of循环

//可迭代对象
let arr = ['foo','bar']

//迭代器工厂函数
console.log(arr[Symbol.iterator]);

//迭代器
let iterator = arr[Symbol.iterator]();
for(let i of arr){
    
}
for(let i of iterator){
    
}