JS-ES6-yield
1. yield
执行过程
1.1 示例 1
- 观察下面代码
js
if (1) {
function* generator() {
const value1 = yield 1
console.log('generator received:', value1)
const value2 = yield 2
console.log('generator received:', value2)
yield 3
}
const gen = generator()
console.log('outside', gen.next()) // { value: 1, done: false }
console.log('outside', gen.next('foo')) // generator received: foo, { value: 2, done: false }
console.log('outside', gen.next('bar')) // generator received: bar, { value: 3, done: false }
console.log('outside', gen.next()) // { value: undefined, done: true }
}
- 问题 1:
foo
传递到了哪里?
[!question]
- 在首次执行 gen.next() 的时候,函数会在 yield 1 处暂停,在调用 gen.next('foo') 的时候,函数应该已经从 console.log('generator received:', value1); 这一行开始执行了,那么,此时的 value1 应该是 undefined 才对,'foo' 参数究竟传入到了哪里
- 实际上,理解这个问题需要明确整个执行过程
- 首先,调用
gen.next()
的时候,yield
表达式暂停了generator
函数的执行过程,同时,generator
生成出来的的Iterator
迭代器,也就是gen
变量,在调用next()
的时候,其结果就是{value: 1, done: false}
。那么,此时的value1
还是undefined
- 然后,调用
gen.next('foo')
的时候,const value1 = yield 1
表达式,会从上一次暂停的状态恢复执行,此时,value1
会看next()
方法是否具备入参。这里,自然是具备的,入参就是'foo'
,那么,之前被暂停的yield
的返回值,就是'foo'
。执行到const value2 = yield 2
的时候又会停住,gen.next('bar')
的调用结果就是{value: 2, done:false}
gen.next(bar)
调用的过程基本上同理,最后在yield 3
这里暂停- 最后一次
gen.next()
已经没有yield
可供消耗了,因此其value
为undefined
- 首先,调用
- 问题 2: 首次调用
gen.next()
的时候如果提供入参,比如,gen.next('hello')
存在意义吗? - 不存在,因为入参的含义是 恢复上次执行时的
yield
表达式,并指定其返回值。既然是首次调用next
,那么一定不存在 上次执行 时的yield
表达式。
1.2 示例 2
js
if (0) {
function* generatorFunction() {
let x = 1
let y = yield x // e1
console.log('y', y) // e2
y = yield y + 2 // e3
return y
}
let generator = generatorFunction()
console.log(generator.next()) // { value: 1, done: false }
console.log(generator.next(10)) // { value: 12, done: false }
console.log(generator.next(20)) // { value: 20, done: true }
/**
* 1. generator.next() 调用 e1, x 成为 iterator.next() 返回对象的value
***** let y = yield x, y 此时还是undefined,因为 Iterator.next() 没有指定入参
* 2. generator.next(10) 还是从e1所在的地方恢复执行, 此时 y 成为 10
***** 触发了 console.log('y', y), 输出 'y' 10
***** 执行 y = yield y + 2, 返回 generator.next(10), 也就是 {value: 12, done: false}
* 3. generator.next(20) 从e2处恢复执行, 此时,y变成了20, 后面执行的过程同上
*/
}
2. 关于 MDN
当中的描述
2.1 MDN
原文
2.2 关于 MDN
示例代码
js
function* counter(value) {
let step
while (true) {
step = yield value++
if (step) {
value += step
}
}
}
const generatorFunc = counter(0)
console.log(generatorFunc.next().value) // 0
console.log(generatorFunc.next().value) // 1
console.log(generatorFunc.next().value) // 2
console.log(generatorFunc.next().value) // 3
console.log(generatorFunc.next(10).value) // 14
console.log(generatorFunc.next().value) // 15
console.log(generatorFunc.next(10).value) // 26
- 显然,上面的代码当中,
if(step)
并不是每次都被触发,只有next(10)
这种提供入参的调用,step
作为 上一次 yield 表达式的返回值 才能被赋值为10
js
function* fibonacci() {
var fn1 = 0
var fn2 = 1
while (true) {
var current = fn1
fn1 = fn2
fn2 = current + fn1
var reset = yield current
if (reset) {
fn1 = 0
fn2 = 1
}
}
}
var sequence = fibonacci()
console.log(sequence.next().value) // 0
console.log(sequence.next().value) // 1
console.log(sequence.next().value) // 1
console.log(sequence.next().value) // 2
console.log(sequence.next().value) // 3
console.log(sequence.next().value) // 5
console.log(sequence.next().value) // 8
console.log(sequence.next(true).value) // 0
console.log(sequence.next().value) // 1
console.log(sequence.next().value) // 1
console.log(sequence.next().value) // 2
- 此处亦然,
reset
只有在next
具备入参的条件下才拥有具体数值,进而通过next(true)
触发重设