前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript迭代器 | 8月更文挑战

JavaScript迭代器 | 8月更文挑战

作者头像
大熊G
发布2022-11-14 16:46:07
2060
发布2022-11-14 16:46:07
举报

theme: channing-cyan highlight: arduino-light


理解迭代

在软件开发领域,迭代的意思就是按照顺序反复并且多次执行一段程序,在JavaScript中,计数循环就是一种最简单的迭代,直接上代码

代码语言:javascript
复制
for (let i = 1;i < 5;i++){
       console.log(i) //1 2 3 4
 }

循环是迭代机制的基础,因为它可以指定迭代的次数,每次迭代执行什么操作,及多会儿停止迭代

ES5新增了Array.prototype.forEach()方法,可以进行单独记录索引及通过数组对象取得值(不够理想)因为这个方法只适用于数组,且回调比较笨拙,也无法标记何使终止。

代码语言:javascript
复制
let collection = ['name','age','six'];
collection.forEach( (item) => console.log(item));//name age six

迭代器

迭代器是按需创建的一次性对象,每个迭代器都会关联一个可迭代对象,迭代器会暴露其关联可迭代对象的API

任何实现iterable接口的数据结构都可以被实现iterator接口的结构进行迭代。

可迭代协议

实现 Iterable 接口(可迭代协议)要求同时具备两种能力:支持迭代的自我识别能力和创建实现 Iterator 接口的对象的能力。在 ECMAScript 中,这意味着必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的 Symbol.iterator 作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。

字符串、数组、映射、集合、arguments对象、NodeList等DOM集合类型都实现了iterable接口

代码语言:javascript
复制
let str = 'abc';
let arr = ['a', 'b', 'c'];
let map = new Map().set('a', 1).set('b', 2).set('c', 3); 
let set = new Set().add('a').add('b').add('c'); 
let els = document.querySelectorAll('div');
// 这些类型都实现了迭代器工厂函数
console.log(str[Symbol.iterator]); // f values() { [native code] } 
console.log(arr[Symbol.iterator]); // f values() { [native code] } 
console.log(map[Symbol.iterator]); // f values() { [native code] } 
console.log(set[Symbol.iterator]); // f values() { [native code] } 
console.log(els[Symbol.iterator]); // f values() { [native code] }
// 调用这个工厂函数会生成一个迭代器
console.log(str[Symbol.iterator]()); // StringIterator {} 
console.log(arr[Symbol.iterator]()); // ArrayIterator {} 
console.log(map[Symbol.iterator]()); // MapIterator {} 
console.log(set[Symbol.iterator]()); // SetIterator {} 
console.log(els[Symbol.iterator]()); // ArrayIterator {}

迭代器协议

迭代器 API 使用 next()方法 在可迭代对象中遍历数据。每次成功调用 next(),都会返回一个 IteratorResult 对象,其中包含迭代器返回的下一个值。若不调用 next(),则无法知道迭代器的当前位置。

next()方法返回的迭代器对象 IteratorResult 包含两个属性:done 和 value。done 是一个布尔值,表示是否还可以再次调用 next()取得下一个值;value 包含可迭代对象的下一个值(done 为 false),如果value的值为 undefined(done 为 true)。done为true的话表示没有下一个了。

代码语言:javascript
复制
        let collection = ['name','age','six'];
        let item = collection[Symbol.iterator]();
        console.log(item);//Array Iterator {}
        console.log(item.next());//{value: "name", done: false}
        console.log(item.next());//{value: "age", done: false}
        console.log(item.next());//{value: "six", done: false}
        console.log(item.next());//{value: undefined, done: true}

迭代器是使用游标来记录遍历可迭代对象的,如果在迭代期间被修改,迭代器也会马上反映相应的变化

代码语言:javascript
复制
let arr = ['foo', 'baz']; 
let iter = arr[Symbol.iterator]();
console.log(iter.next());// { done: false, value: 'foo' } 
// 在数组中间插入值
arr.splice(1, 0, 'bar'); 
console.log(iter.next()); // { done: false, value: 'bar' } 
console.log(iter.next()); // { done: false, value: 'baz' } 
console.log(iter.next()); // { done: true, value: undefined }

注意:迭代器维护着一个指向可迭代对象的引用,因此迭代器会阻止垃圾回收程序回收可迭代对象。

提前终止迭代器

一般我们用return()方法来关闭执行迭代的逻辑。return方法必须返回一个返回值,我们可以只返回 done:true

代码语言:javascript
复制
        let a = [1, 2, 3, 4, 5]; 
        let iter = a[Symbol.iterator](); 
        iter.return = function() { 
            console.log('Exiting early'); 
            return { done: true }; 
        };
        for (let i of iter) { 
            console.log(i); 
            if (i > 2) { 
            break 
            } 
        } 
        //1 2 3 Exiting early

for-of循环也可以过过berak、continue、return、throw提前退出

代码语言:javascript
复制
        let counter = [1,2,3,4,5];
        for( let i of counter){
            if(i>3){
                break;
            }
            console.log(i);
        }

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

代码语言:javascript
复制
     let counter = [1,2,3,4,5];
     for( let i of counter){
            console.log(i);
            if(i>3){
                break  
            }
            //1 2 3
        }
        for( let i of counter){
            console.log(i);
        }//4 5

自定义迭代器

为了让一个可迭代对象能够创建多个迭代器,必须每创建一个迭代器就对于一个新计数器,为此我们可以把计数器变量放到闭包里,然后通过闭包返回迭代器

代码语言:javascript
复制
        class Counter { 
        constructor(limit) { 
            this.limit = limit; 
            } 
            [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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解迭代
  • 迭代器
    • 可迭代协议
      • 迭代器协议
        • 提前终止迭代器
          • 自定义迭代器
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档