• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

迭代器与生成器

开发技术 开发技术 3小时前 2次浏览

迭代就是遍历一个东西,不一定要遍历完。


为什么需要迭代器?因为使用循环来迭代不理想,具体有两方面原因:

  • 迭代之前需要事先知道如何使用数据结构。如利用数组下标[]来取得特定索引位置上的项
  • 遍历顺序并不是数据结构固有的。如通过递增索引来访问数据,只有数组能这样

我们需要的是一种通用迭代方式,能对自己定义的任何对象进行迭代的方法。这个方法就是使用迭代器


这里需要分清三个概念:可迭代对象、迭代器工厂函数、迭代器:

let str = ['a','b','c']; // 可迭代对象
console.log(str[Symbol.iterator]) // 打印出迭代器工厂函数
console.log(str[Symbol.iterator()]) // 调用迭代器工厂函数会生成一个迭代器

 

实现迭代器接口意味着该可迭代对象有个 Symbol.iterator 键(作为默认迭代器属性),它引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。JS中实现迭代器接口的对象有 String Array Map Set DOM, 这些对象在如 for – of 等语法下会自动调用迭代器工厂函数创建迭代器,然后调用迭代器的 next 方法,返回一个对象包含 done 和 value:

class Counter{
        constructor(limit){
            this.limit=limit;
        }

        // 这就叫实现了迭代器接口,它返回一个迭代器对象,next是其方法
        [Symbol.iterator](){
            let count=1,
                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)} // 1 2 3
    for(let i of counter){console.log(i)} // 1 2 3

return() 方法可以用来提前关闭迭代器,当 for-of 结构遇到 break、continue、return 、throw 提前退出:

class Counter{
        constructor(limit){
            this.limit=limit;
        }

        // 这就叫实现了迭代器接口,它返回一个迭代器对象,next是其方法
        [Symbol.iterator](){
            let count=1,
                limit=this.limit;
            return {
                next(){
                    if(count<=limit){
                        return {done:false,value:count++};
                    }else{
                        return {done:true,value:undefined};
                    }
                },
                return(){
                    console.log('提前退出');
                    return {done:true};
                }
            }
        }
    }

    let counter = new Counter(3);

    for(let i of counter){
        if(i>2){
            break;
        }
        console.log(i);  
    }
    // 1 2 提前退出

如果迭代器没有关闭,还可以继续从上次离开的地方开始迭代:

let a = [1,2,3,4,5];
    let iterator = a[Symbol.iterator](); // 返回迭代器

    for(let i of iterator){
        console.log(i);
        if(i>2){
            break;
        }
    }
    // 1 2 3
    for(let i of iterator){
        console.log(i);
    }
    // 4 5

数组的迭代器是不能关闭的,即使给它增加一个 return 方法也不行。

 


程序员灯塔
转载请注明原文链接:迭代器与生成器
喜欢 (0)