You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function*innerGeneratorFn(){yield'foo';return'bar';}function*outerGeneratorFn(genObj){console.log('iter value:',yield*innerGeneratorFn());}for(constxofouterGeneratorFn()){console.log('value:',x);}// value: foo// iter value: bar
理解迭代
迭代器模式
任何实现 Iterable 接口的数据结构都可以被实现 Iterator 接口的结构“消费”(consume)。迭代器(iterator)是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,而迭代器会暴露迭代其关联可迭代对象的 API。
接收可迭代对象的原生语言特性包括:
迭代器协议
next()方法返回的迭代器对象 IteratorResult 包含两个属性:done 和 value。done 是一个布尔值,表示是否还可以再次调用 next()取得下一个值;value 包含可迭代对象的下一个值(done 为false),或者 undefined(done 为 true)。done: true 状态称为“耗尽”
自定义迭代器
这个类实现了 Iterator 接口,但不理想。这是因为它的每个实例只能被迭代一次
提前终止迭代器
生成器
生成器是 ECMAScript 6 新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力
生成器的形式是一个函数,函数名称前面加一个星号(*)表示它是一个生成器。
调用生成器函数会产生一个生成器对象。生成器对象一开始处于暂停执行(suspended)的状态。与迭代器相似,生成器对象也实现了 Iterator 接口,因此具有 next()方法。调用这个方法会让生成器开始或恢复执行。
函数体为空的生成器函数中间不会停留,调用一次 next()就会让生成器到达 done: true 状态。
生成器函数只会在初次调用 next()方法后开始执行
通过 yield 中断执行
yield 关键字可以让生成器停止和开始执行,也是生成器最有用的地方。生成器函数在遇到 yield关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域的状态会被保留。停止执行的生成器函数只能通过在生成器对象上调用 next()方法来恢复执行
通过 yield 关键字退出的生成器函数会处在 done: false 状态;通过 return 关键字退出的生成器函数会处于 done: true 状态
生成器函数内部的执行流程会针对每个生成器对象区分作用域。
生成器对象作为可迭代对象
使用 yield 实现输入和输出
产生可迭代对象
使用 yield*实现递归算法
生成器对象作为可迭代对象
通过一个简单的循环来实现
第一次调用 next()传入的值不会被使用,因为这一次调用是为了开始执行生成器函数
yield 关键字可以同时用于输入和输出
定义了一个无穷计数生成器函数
这样使用生成器也可以实现范围和填充数组:
因为 yield*实际上只是将一个可迭代对象序列化为一连串可以单独产出的值
yield*的值是关联迭代器返回 done: true 时的 value 属性。对于普通迭代器来说,这个值是undefined:
对于生成器函数产生的迭代器来说,这个值就是生成器函数返回的值:
yield*最有用的地方是实现递归操作,此时生成器可以产生自身。
使用递归生成器结构和 yield*可以优雅地表达递归算法。下面是一个图的实现,用于生成一个随机的双向图
图数据结构非常适合递归遍历,而递归生成器恰好非常合用。为此,生成器函数必须接收一个可迭代对象,产出该对象中的每一个值,并且对每个值进行递归。
这个实现可以用来测试某个图是否连通,即是否没有不可到达的节点。只要从一个节点开始,然后尽力访问每个节点就可以了。
结果就得到了一个非常简洁的深度优先遍历
生成器作为默认迭代器
因为生成器对象实现了 Iterable 接口,而且生成器函数和默认迭代器被调用之后都产生迭代器,所以生成器格外适合作为默认迭代器。下面是一个简单的例子,这个类的默认迭代器可以用一行代码产出类的内容:
提前终止生成器
一个实现 Iterator 接口的对象一定有 next()方法,还有一个可选的 return()方法用于提前终止迭代器
还有第三个方法:throw()。
return()和 throw()方法都可以用于强制生成器进入关闭状态。
return()方法会强制生成器进入关闭状态。提供给 return()方法的值,就是终止迭代器对象的值
与迭代器不同,所有生成器对象都有 return()方法,只要通过它进入关闭状态,就无法恢复了。后续调用 next()会显示 done: true 状态,而提供的任何返回值都不会被存储或传播
throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。
不过,假如生成器函数内部处理了这个错误,那么生成器就不会关闭,而且还可以恢复执行。错误处理会跳过对应的 yield
生成器在 try/catch 块中的 yield 关键字处暂停执行。
在暂停期间,throw()方法向生成器对象内部注入了一个错误:字符串"foo"。
这个错误会被 yield 关键字抛出。因为错误是在生成器的 try/catch 块中抛出的,所以仍然在生成器内部被捕获。
可是,由于 yield 抛出了那个错误,生成器就不会再产出值 2。
🆗
The text was updated successfully, but these errors were encountered: