一.说明
yield 关键字用来暂停和继续执行一个生成器函数。
(1).yield的功能:
1. 与return类似,都可以返回值,不一样在于,yield可以返回多个值而且可暂停,再次执行可继续下一步操作,return到了就停止不在继续运行。
2.为封装好的的函数能够使用__iter__和__next__方法,
3.遵循迭代器的取值方式 .__next__(),触发函数的执行和函数的保存都是通过yeild保存的。
(2).yield表达式, 四种形式:
a. 不接受输入值或者输入值是None
yield 1
b. 接受输入值
s = yield 1
c. 接受输入,但不返回数据,这样默认返回None
s = yield
d.既不接受输入,也不返回值,默认返回None
yield
第一种:当函数调用到yield时,返回yield的右边经过计算的值 ,这里说计算的意思是,yield后面可以写成函数,表达式等,
第二种:当函数调用到yield时,必须传入一个值,该值存入s中,然后返回yield后面的表达式的值并保存当前状态
第三种:只是将数据接受进来,然后执行yield后的语句,再次执行到yield时,保存当前状态并返回,这样的用例一般是
只打印一些处理消息,而不需要结果的方式。
第四种:这样的只能遍历generator内部的数据了。
二.理解与next()
1.当外部调用生成器的 next() 方法时,yield 关键字右侧的表达式才会执行。执行结果会转化为一个对象(包含两个属性, value 和 done),作为 next() 方法的返回值。对于 var foo = yield expression 语句,yield 左侧变量 foo 的值将在下一次调用 next() 方法时获得,并且等于调用时 next() 方法的参数。
function* numbers() {
console.log('function start.');
var v1 = yield 0;
console.log('v1 = ' + v1);
var v2 = yield 1;
console.log('v2 = ' + v2);
var v3 = yield 4;
console.log('v3 = ' + v3);
return 10;
}
var nums = numbers();
//调用生成器函数
// 第 1 次调用 next, v1 的值还没有返回.
nums.next(1)
输出: function start. {value: 0, done: false}
// 第 2 次调用 next, next 参数作为上一次 yield 值返回给 v1.
nums.next(1)
输出:v1 =1 { value: 1, done: false }
// 第 3 次调用 next, next 参数作为上一次 yield 值返回给 v2.
nums.next(2)
输出:v2 =2 { value: 4, done: false }
// 第 4次调用 next, 此时 done 的值为 true, 直接返回 return 的值.
nums.next(4)
输出:v3 = 4 { value: 10, done: true }
2.如果yield表达式后面跟的是一个遍历器对象,需要在yield表达式后面加上星号,表明它返回的是一个遍历器对象。这被称为yield*表达式。
function* inner() {
yield 'a';
yield 'b';
}
function* outer1() {
yield 'x';
yield inner();
yield 'y';
}
var gen = outer1()
gen.next().value // "x"
gen.next().value // 返回一个遍历器对象 inner {<suspended>}
gen.next().value // "y"
gen.next().value // undefined
function* outer2() {
yield 'x'
yield* inner()
yield 'y'
}
var gen = outer2()
gen.next().value // "x"
gen.next().value // "a"
gen.next().value // "b"
gen.next().value // "y"
gen.next().value // undefined
3.如果yield*
后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员
function* gen(){
yield* ["a", "b", "c"];
}
gen().next() // { value:"a", done:false }
上面代码中,yield
命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。
实际上,任何数据结构只要有 Iterator 接口,就可以被yield*
遍历。
let read = (function* () {
yield 'hello';
yield* 'hello';
})();
read.next().value // "hello"
read.next().value // "h"
三.for...of循环
for...of循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法。for...of循环的基本语法是:
for (let v of foo()) {
console.log(v);
}
其中foo()是迭代器对象,可以把它赋值给变量,然后遍历这个变量。
把上面的例子可以修改如下:
function* inner() {
yield 'a';
yield 'b';
}
function* outer1() {
yield 'x';
yield inner();
yield 'y';
}
console.log('yield表达式:')
for (let v of outer1()){
console.log(v);
}
console.log('yield*表达式:')
function* outer2() {
yield 'x'
yield* inner()
yield 'y'
}
for (let v of outer2()){
console.log(v);
}
// yield表达式:
x
inner {<suspended>}
y
//yield*表达式:
x
a
b
y