ES6的yield是如何执行接受参数的

作者:日期:2017-03-25 16:54:25 点击:1247

 我们先回顾一下这个经常被用来演示yield语法的函数例子

function* gen () {
for (let i = 0; i < 5; i++) {
yield i
}
}

const g = gen();
g.next() // {value: 0, done:false}
g.next() // {value: 1, done:false}
g.next() // {value: 2, done:false}
g.next() // {value: 3, done:false}
g.next() // {value: 4, done:false}
g.next() // {value: undefined, done:true}

哎哟,不错哦?这看起来还挺炫的嘛,next()一次执行一次诶!这个语法有意思。随即,我们来到了一个稍微复杂一点的例子:

function * gen () {
console.info('执行 A')
let x = yield 1
console.info('执行 B, X is :' + x)
let y = x + (yield 5)
console.info('执行 C')
yield y
console.info('执行 D')
console.info('Y is :' + y);
}

const g = gen()
g.next()
// >> 执行 A
// >> {value: 1, done:false}
g.next(2)
// >> 执行B, X is : 2
// >> {value: 5, done:false}
g.next(3)
// >> 执行 C
// >> {value: 5, done:false}
g.next(5)
// >> 执行 D
// >> Y is :5
// >> {value: undefined, done:true}

开始有点云里绕的感觉了,g.next(2) 做了什么?我们知道答案:g.next(2)给yield传入了值。也就是说yield不仅可以将值传出,还可以接受从外面传入的值,这里面其实有一个比较混淆的地方,yiele从值是从哪一步传入的?传之后的函数执行实际上张什么样子呢?我们一步步地看看:

1. 函数调用: const g = gen()

调用函数gen,并获得了执行 yield 的句柄,但是函数本身并没有被执行。我们可以看到,在第一个g.next()执行以前,console.info(‘执行 A’)并没有执行,因此函数处于待执行状态。

2. 第一个next: g.next()

开始执行函数了,且执行到第一个yield语句刚刚结束,同时获取yield语句的返回值。因此我们看到第一个console语句执行了,且得到了第一个yield的返回值,然后停下来。

But wait! 什么叫“yield语句的返回值”? 我们知道 yiled 1 会返回1, 那如果yield后面是一个表达式呢,比如↓↓:

let x = 1 + yield (2 + 3) + 4

答案是:语法错误, 但这并不能说明yield错了。。错的是解析器(解析器→_→ 怪我咯?),我们换个写法:

let x = 1 + (yield (2 + 3 )) + 4

这样就可以了,答案我想大家也猜到了,那就是会返回5,因为这就是后面表达式的返回值。

3. 第二个next: g.next(2)

这次我们不仅执行了next(),而且传入了参数2。从后面的打印语句,我们可以看到这个2给了 X 这变量。但还是表象,因为2其实是赋值给了 yield 1 这个语句,只是因为 x = yield 1 从而把这个2 又再赋值给了x。也就是说,next()的参数会被赋值给 yield语句。

因此同理,如果我们的yield语句是 (yield (2 + 3)), 在我们调用 g.next(9) 之后,效果相当于(yield ( 2 + 3 )) === 9。实际上,这个赋值语句是很有必要的,如果没有这里面的 g.next(2), 我们的x的值就会是 undefined, yield语句的执行本身并没有值。

4. 第三个next: g.next(3)

同第二个类似,next()执行了下一个yield语句,并立即停止执行了。它得到了该yield语句的返回值5,并停下来。这里面的x赋值已经完成了,就是上面设置过的2。

5. 第四个next: g.next(5)

执行了第三个yield语句 yield y, 并获得了y的值,即前面被赋值了的 x(2) + y (3), 结果等于5。由于这是最后一个yield语句,他返回的 {done: true}, 返回结果是最后执行的。

说了这么多next()和yield语句的细节是要干嘛

其实是我自己在看到他们的时候犯怵。看到他们传入了参数,但是参数是在哪一步被传入的?yield语句执行的效果到底什么?其实困惑着我,让我没怎么好意思去问和思考进一步的问题,比如使用场景,现在我们可以肯定地说出如下:

next()的参数怎么传值的?

其实理解为传入有点不太贴切,传入还是我们现有的思维,仿佛函数的参数传入那么理解就有点跟不上了(当然next传值也是函数的参数=_=)。我觉得把这个 next()的参宿理解为赋值更贴切,为上一个yield语句赋值。那么为什么不在上一个yield语句执行的同时就赋值呢?这就是他令人困惑的地方啊。。

yield语句是什么?

yield其实就是一个新的JavaScript关键字,他的作用是执行后面的表达式。他的这种表达式执行我们其实见过一个类似的,那就是typeof,typeof也是这么执行的嘛!而且也是返回执行的结果,不过typeof结果返回结果是直接在当前整个表达式中的,而yield语句的返回结果是给next()的,而且他自身在表达式中返回 undefined, 除非我们我们在调用next()的时候传入了值。

上一篇: JS模块(module)、加载(load)与捆绑(bundle)简介

下一篇: javascript事件基础学习笔记