写点什么

JavaScript 迭代器

作者:大熊G
  • 2022 年 6 月 05 日
  • 本文字数:2645 字

    阅读完需:约 9 分钟

JavaScript迭代器

理解迭代

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

for (let i = 1;i < 5;i++){       console.log(i) //1 2 3 4


复制代码

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

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

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 接口

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 的话表示没有下一个了。

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}

复制代码

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

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


 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 提前退出

   let counter = [1,2,3,4,5];        for( let i of counter){            if(i>3){                break;            }            console.log(i);        }




复制代码

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

     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
复制代码


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

        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
复制代码


发布于: 刚刚阅读数: 3
用户头像

大熊G

关注

每天都在写bug的硬核男人 2022.06.02 加入

前端

评论

发布
暂无评论
JavaScript迭代器_JavaScript_大熊G_InfoQ写作社区