一、理解迭代:
循环是迭代机制的基础;迭代会在一个有序的集合上进行
通过循环执行迭代并不理想:
迭代之前需要事先知道如何使用数据结构:如数组需要通过索引取值
遍历顺序并不是数据结构固有的
迭代器模式:开发者不需要事先知道如何迭代就能实现迭代操作
二、迭代器模式
迭代器模式:描述了一个方案,把实现了iterable接口的结构称为可迭代对象,可以通过迭代器iterator消费
可迭代对象:包含有限的元素;具有无歧义的遍历顺序
(临时性可迭代对象可以实现为生成器)
迭代器是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,迭代器暴露其关联的可迭代对象的api.
可迭代协议(Iterable):要求具备一下两种能力,
支持迭代的自我识别;创建实现了Iterator接口的对象的能力
在ECMAScript中,意味着必须暴露一个属性作为“默认迭代器”,这个属性必须以Symbol.iterator作为键
这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数返回一个新迭代器
实现了Iterable的内置对象:字符串、数组、映射、集合、arguments对象、NodeList等DOM集合类型
console.log(arr[Symbol.iterator]()) // ArrayIterator
实现了可迭代协议的所有类型都会自动兼容接受可迭代对象的任何语言特性。接受可迭代对象的原生语言特性有:
for-of
数组解构
扩展操作符
Array.from()
创建集合
创建映射
Promise.all()
Promise.race()
yield*操作符
如果对象原型链上的父类实现了Iterable接口,那这个对象也实现了这个接口
迭代器协议:迭代器是一种一次性使用的对象,用于迭代与其关联的可迭代对象;迭代器使用next()方法在可迭代对象中遍历数据;
成功调用时返回一个IteratorResult对象,包含两个属性done和value,done为true时状态为耗尽;value为下一个值或者undefined
不同迭代器实例互相之间没有任何联系,每个迭代器只会独立的遍历可迭代对象
迭代器并不用某个时刻的可迭代对象的快照绑定,如果迭代期间可迭代对象被修改,迭代器也会反映相应的变化。
迭代器维护着一个可迭代对象的引用,会阻止垃圾回收
自定义迭代器: 任何实现了Iterator接口的对象都可以作为迭代器使用
每个 由可迭代对象的Symbol.iterator工厂函数实现的 迭代器也实现了Iterable接口,Symbol.iterator属性引用的工厂函数会返回相同的迭代器
提前终止迭代器
可选的return()方法用于指定在迭代器提前关闭时执行的逻辑
可能的情况包括:循环中break continue return和throw
解构操作并未消费所有的值
return()方法需要返回一个有效的IteratorResult对象
如果迭代器没有关闭,可以从上次离开的地方继续迭代,如数组的迭代器就不能关闭
测试迭代器实例有没有return方法可以判断能否关闭
仅仅添加return方法不能让它变成可关闭的,因为调用return方法不会强制迭代器进入关闭状态
三、生成器
生成器是一个ES6新增的极为灵活的结构,拥有在一个函数块里暂停和恢复代码执行的能力
基础:
生成器的形式是一个函数,函数名前面加上一个*,表示是一个生成器
箭头函数不能定义生成器
生成器对象:调用生成函数会产生一个生成器对象,该对象一开始处于暂停执行的状态(suspended)
生成器对象实现了Iterator接口,因此具有next()方法,调用next()会让生成器开始或者恢复执行
next()返回值类似于迭代器,有一个done和value属性。函数体为空的函数中间不会停留,调用一次就会到done=true的状态
生成器对象实现了Iterator接口,默认的迭代器是自引用
通过yield中断执行
yield关键字可以让生成器停止和开始执行
yield生成的值,会在next()方法返回的对象里,通过yield关键字退出的生成器函数会处在done=false状态,通过return 关键字退出的为done=true
生成器函数内部执行流程会针对每个生成器对象区分作用域
yield关键字只能在生成器函数内部使用,其他地方会抛错
1.生成器对象可以作为可迭代对象
2.使用yield关键字实现输入输出
上一次让函数暂停的yield关键字会接受到传给next()方法的第一个参数。而第一次调用next()方法传入的值不会被使用
3.可以使用星号增强yield的行为,让它能够迭代一个可迭代对象,从而一次产出一个值
Yield * 的值是关联迭代器返回done:true的value值
4.使用yield*实现递归算法
生成器作为默认迭代器。生成器函数和默认迭代器被调用后都产生迭代器。
提前终止生成器:
生成器除了有next()和return()方法外,还有一个throw()方法。Return()和throw()方法都可以强制让生成器进入关闭状态
1.return():所有生成器都有这个方法,只要通过它进入关闭状态,就无法恢复,后续调用next()会显示done:true
for-of等结构会忽略状态为done:true的IteratorResult内部返回值
2、throw()方法会在暂停的时候将一个提供的错误注入生成器对象,如果错误未被处理,生成器会被关闭。如果生成器函数内部处理了这个错误,则不会关闭。如果生成器对象还没有开始执行,调用throw()抛出的错误不会再函数内部被捕获,因为相当于在函数块外部抛出错误。