在 generator 函数内部,通过yield*语句,可以将yield委托给其他任何实现iterable的对象。
委托给 generator 函数生成的iterable对象
调用 generator 函数会返回一个实现iterable的对象(该对象同时也是一个iterator)。
通过yield* otherGenerator()可以将 generator 内的yield委托给其他 generator 生成的iterable对象。
1 | function* foo() { |
可以看到上面的代码中,在调用第 3 个next方法时返回的是foo里面yield的"foo 1";在调用第 5 个next时,并没有返回foo generator 隐式return的undefined,而是返回了"bar 3"。
如果foo内有显式的return语句,那么在进行 yield-delegation 时是否会返回foo return的值吗?
下面的代码在foo中添加了一个return语句。在bar内将yield* foo()表达式的值赋值给tmp变量并打印。
1 | function* foo() { |
在第 5 次调用next方法时,可以发现foo return的"foo 3"变成了yield* foo()表达式的值,并被打印为"在bar内打印 foo 3";"bar 3"成为next方法的返回值。
委托给其他任何实现iterable的对象
generator 内部的yield*语句也能将yield委托给其他非 generator 生成的iterable对象。例如 数组就是一个实现了iterable的对象。
1 | function* bar() { |
也可以委托给自己手写的iterable对象。由于 javascript 不是强类型语言,如果对象上含有Symbol.iterator方法,那么就可以将该对象当做一个iterable对象;如果对象上含有next方法,那就可以将该对象当做一个iterator对象。下面的myIterable对象即实现了Symbol.iterator方法也实现了next方法,所以它即是一个iterable又是一个iterator。
1 | var myIterable = { |
异常委托
被委托的iterator内部执行过程发生异常,如果异常被捕获,那么捕获处理完异常后还按原来的逻辑运行;如果异常未被捕获,那么异常会被抛出,异常会被抛到yield*语句那。下面是《YOU DON’T KNOW JS》内的例子。
1 | function* foo() { |
递归委托
下面是《YOU DON’T KNOW JS》里的例子。
1 | function* foo(val) { |