在软件开发领域,“迭代”的意思是按照顺序反复执行一段程序,通常会有明确的终止条件。ECMAScript6规范新增了两个高级特性:迭代器和生成器。使用这两个特性,能够更清晰、高效、方便地实现迭代。
理解迭代
在JavaScript中,技术循环就是一种最简单的迭代👇
for(let i=1; i<=10; ++i){
console.log(i);
}
循环是迭代的基础,因为可以指定迭代的次数,以及每次迭代要执行什么操作。
迭代会在一个有序集合上进行。数组是JavaScript中有序集合的最典型例子。
let collection = ['1','2','3'];
for(let i=0; i<collection.length; ++i){
console.log(collection[i]);
}
⚪迭代之前需要事前知道如何使用数据结构。数组中的每一项都先通过引用取得数组对象,然后再通过[]操作符取得特定索引位置上的项。
⚪遍历顺序并不是数据结构固有的。通过递增索引访问数据是特定域数组类型的方式,并不适用于其他具有隐式顺序的数据结构。
ES5新增了Array.prototype.forEach()方法(但仍然不够理想)。JavaScript在ECMAScript6以后也支持了迭代器模式。
迭代器模式
迭代器模式(特别是在ECMAScript这个语境下)描述了一个方案,即可以把有些结构成为“可迭代对象”,因为他们实现了正式的`Iterable`接口,而且可以通过迭代器`Iterable`消费。迭代器是是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的API。迭代器不需要知道与其关联的可迭代对象的结构,只需要知道如何取得连续的值。
1.可迭代协议
满足可迭代协议就可以运用迭代器的功能,可迭代协议就是Iterable接口,需要同时具备两个能力:支持迭代的自我识别能力和创建实现Iterable接口的对象的能力。在ECMAScript中,这意味着必须暴露一个属性作为“默认迭代器”,而这个属性必须使用特殊的Symbol.iterator作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。
很多内置类型都实现了Iterable接口:字符串,数组,映射,集合,argument对象,NodeList等DOM集合类型。
在实际写代码的过程中,不需要显式调用这个工厂函数来生成迭代器。实现可迭代协议的所有类型都会自动兼容接收可迭代对象的任何语言特性。接受可迭代对象的原生语言特性包括👇
for-of循环、数组解构、扩展操作符、Array.from()、创建集合、创建映射、Promise.all()接收由期约组成的可迭代对象、Promise.race()接收由期约组成的可迭代对象和yield*操作符,在生成器中使用。
2.迭代器协议
迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象。迭代器API使用`next()`方法在可迭代对象中遍历数据。每次成功调用`next()`,都会返回一个`IteratorResult`对象,其中包括迭代器返回的下一个值。如果不调用next()就不知道迭代器当前的位置。next()方法返回的迭代器对象包含两个属性:done和value。
⚪done:返回一个布尔值,表示是否可以继续调用next()却的下一个值。true状态为耗尽,value为undefine。false状态👇
⚪value:包含可迭代对象的下一个值。
每个迭代器都表示对可迭代对象的一次有序遍历,不同迭代器的实例相互之间没有联系,只会独立地遍历可迭代对象。并且,如果可迭代对象在迭代期间被修改,那么迭代器依旧可以反应相应的变化。
3.自定义迭代器
与Iterable接口类似,任何实现接口的对象都可以作为迭代器使用。
4.提前终止迭代器
for-of循环通过break、continue、return或throw提前退出
结构操作并为消费所有的值
生成器
生成器是ECMAScript6新增的一个极为灵活的结构,拥有一个函数块内暂停和回复代码执行的能力。
1.生成器基础
生成器的形式是一个函数,函数名称前加一个星号(*)表示它是一个生成器。只要是可以定义函数的地方,就可以定义生成器👇//生成器函数声明
function* generatorFn(){}
//生成器函数表达式
let generatorFn = function*(){}
//作为对象字面量方法的生成器函数
let foo = {
*generatorFn(){}
}
//作为类实例方法的生成器函数
class Foo{
*generatorFn(){}
}
//作为类静态方法的生成器函数
class Bar{
static *generatorFn(){}
}
箭头函数不可以用来定义生成器函数
标识生成器函数的星号不受两侧空格的影响
调用生成器函数会产生一个生成器对象。生成器对象一开始处于暂停执行的状态。与迭代器相似,生成器对象也实现了Iterable接口,因此具有next()方法。调用这个方法会让生成器开始或回复执行。
2.通过yield中断执行
生成器通过yield中断执行,函数作用域的状态会被保留,再通过·next()`方法的调用来恢复执行。
因为这个原因,此时的done状态为false。
生成器与迭代器一样,每个生成器之间相互独立。
文章内容参考:JavaScript高级程序设计(第四版)标题样式来自:juejin.cn/post/684490…
哪里写错了就联系我🐧:54269504