从零开始学_JavaScript_系列(55)——Generator函数(3)yield*表达式
2017-08-23 00:37
495 查看
4、yield*表达式
4.1、基础
简单来说,yield*表达式就是在一个Generator函数内嵌套另外一个Generator函数。于是在遍历的过程中,当在第一个Generator函数内遇见第二个Generator函数后,就会先停止遍历第一个Generator函数,先遍历完第二个Generator函数,然后再恢复。
如代码:
let g1 = function*() { yield 1; yield* g2(); yield 2; } let g2 = function*() { yield "a"; yield "b"; } let foo = g1(); for (let i of foo) { console.log(i) } // 1 // a // b // 2
如上,简单暴力通俗易懂。
假如不是
yield* g2(),而是
yield g2()会发生什么事情呢?
首先,g2()会返回一个遍历器对象,毫无疑问;
其次,yield表达式会使得该遍历器对象作为next的返回值来返回;
因此最终结果是1——》g2()的遍历器——》2,代码就略了不写
4.2、递归
因为yield*表达式的存在,因此遍历器可以递归自己,代码十分简单:let g1 = function*(count) { console.log("count:" + count) if (count > 3) { return } yield 1; yield 2; yield* g1(count + 1); } let foo = g1(1); for (let i of foo) { console.log(i) } // count:1 // 1 // 2 // count:2 // 1 // 2 // count:3 // 1 // 2 // count:4
4.3、有Iterator接口的数据结构
yield*表达式可以遍历Generator函数,原因是Generator函数有Iterator接口,相当于对Generator函数的遍历器执行了for...of;
那么yield*表达式能不能遍历非Generator函数,但是也有Iterator接口的数据结构呢?显然也是可以的。
如代码:
let g1 = function*() { yield* [1, 2] yield* "ab" } let foo = g1(); for (let i of foo) { console.log(i) } // 1 // 2 // "a" // "b"
也可以对自定义数据结构生效,只要他有Iterator接口即可:
function Test() { let arr = [3, 2, 1] function Iterator() { let index = 0 // 该对象有next方法,调用后返回一个当前索引下的值 this.next = function () { let obj = {} if (index < 3) { obj.value = arr[index] obj.done = false index++ } else { obj.value = undefined obj.done = true } return obj } // 返回他自己 return this } // 遍历器接口 this[Symbol.iterator] = function () { // 创建一个遍历器对象(Iterator不是关键词) let temp = new Iterator() // 返回他 return temp } } let m = new Test() let g1 = function*() { yield* m } let foo = g1(); for (let i of foo) { console.log(i) } // 3 // 2 // 1
4.4、返回值
Generator函数是返回值是他的遍历器;遍历器的返回值是对象,有value和done属性;
yield表达式的返回值是根据遍历器的next的参数决定;
那么yield*表达式的返回值是什么呢?
答案是根据被遍历函数的return所决定;
最简单的示例如代码:
let g1 = function*() { console.log(yield* g2()) } let g2 = function*() { yield 'a'; return 'b'; } let foo = g1(); for (let i of foo) { console.log(i) } // 'a' // 'b'
那么,是否还记得Generator函数的返回值在什么时候起作用?
可以回去看看1.1,return是在done第一次变为true时,value属性的值。
因此,yield*的值,取决于遍历器在遍历结束,done变为true时,value属性的值,如以下代码自定义了一个数据结构,这个数据结构在done变为true时是有值的。
function G() { let arr = [3, 2, 1] function Iterator() { let index = 0 this.next = function () { let obj = {} if (index < 3) { obj.value = arr[index] obj.done = false index++ } else { // 这里与之前的例子不同 obj.value = '自定义数据结构的done变为true了' obj.done = true } return obj } } this[Symbol.iterator] = function () { let temp = new Iterator() // 返回他 return temp } } let g = new G() let g1 = function*() { console.log(yield* g) } let foo = g1(); for (let i of foo) { console.log(i) } // 3 // 2 // 1 // "自定义数据结构的done变为true了"
相关文章推荐
- 从零开始学_JavaScript_系列(56)——Generator函数(4)简写,this与继承
- 从零开始学_JavaScript_系列(57)——Generator函数(5)状态机与函数的应用
- 从零开始学_JavaScript_系列(53)——Generator函数(1)基本概念和示例
- 从零开始学_JavaScript_系列(54)——Generator函数(2)简单应用、throw和return
- 从零开始学_JavaScript_系列(16)——js系列<5>(正则表达式)
- 深入理解JavaScript系列(2):揭秘命名函数表达式
- 从零开始学_JavaScript_系列(33)——dojo 的 tree
- 从零开始学_JavaScript_系列(67)——es6的import和export(chrome61版本后可用)
- 从零开始学_JavaScript_系列(六)——CSS的padding、margin、border属性超详细解释(图文)
- 从零开始学_JavaScript_系列(1)——dojo(8)(手把手教你封装一个widget)
- 从零开始学_JavaScript_系列(50)——Promise(3)全部完成all和看谁最快race
- 深入理解JavaScript系列(4):立即调用的函数表达式
- 从零开始学_JavaScript_系列(68)——es6模块的使用
- 深入理解Javascript系列————立即调用的函数表达式
- 深入理解JavaScript系列(2):揭秘命名函数表达式
- JavaScript 字符串与正则表达式系列总结
- 从零开始学_JavaScript_系列(四)——jquery(基础,选择器,触发条件,动画,回调函数)
- 从零开始学_JavaScript_系列(29)——apply和call
- JavaScript内核系列 第6章 正则表达式(转载)
- 深入理解JavaScript系列(2):揭秘命名函数表达式