您的位置:首页 > Web前端 > JavaScript

从零开始学_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了"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐