先看一下生成器的几种声明方法:
function* genFunc() {}//函数声明
let genObj = genFunc();
const genFunc = function* () { };//函数表达式
let genObj = genFunc();
let obj = {//对象字面量
* generatorMethod() {
}
};
let genObj = obj.generatorMethod();
class MyClass {//类方法
* generatorMethod() {
}
}
let myInst = new MyClass();
let genObj = myInst.generatorMethod();
上面创建生成器实例的时候我们并没有使用new操作符,而且直接当函数来调用,规范中明确说明了,用和不用new的效果是一样的:
The GeneratorFunction constructor is the %GeneratorFunction% intrinsic. When GeneratorFunction is called as a function rather than as a constructor, it creates and initializes a new GeneratorFunction object. Thus the function call GeneratorFunction (…) is equivalent to the object creation expression new GeneratorFunction (…) with the same arguments.
yield只能直接使用在生成器函数中:
function* genFunc() {
['a', 'b'].forEach(x => yield x); // Uncaught SyntaxError: Unexpected strict mode reserved word
}
上面这个yield是用在了forEach的回调函数中,并没有直接在生成器函数中,所以会报错。下面这种写法就是OK的:
function* genFunc() {
for (let x of ['a', 'b']) {
yield x;
}
}
yield是个关键字,不是操作符,虽然(yield 3)这种写法看起来像个操作符,但是yield还可以用作赋值操作(var x = yield),这点明显看出它不像个操作符。
yield的优先级很低,所以有一些写法需要特殊注意:
function* genFunc() {
yield 3;
var a = 2 + yield 3; //这种写法是错误的
var b = 2 + (yield 3); //加括号就OK了
}
yield 2 + 3;//等同于yield (2+3)
(yield 2) + 3;
所以在不确定yield优先级的情况下,最好加上括号,这样能保证不出错。yield的结合性是右结合:
yield yield yield 3//等同于yield (yield (yield 3))
yield还可以直接当作函数参数来使用:
foo(yield 'a', yield 'b');
上面林林总总说了一些yield的语法,下面看yield起的作用:
yield主要用途:1)生产数据,2)接收数据
1)生产数据,这个作用大家肯定不陌生,上面的绝大部分例子都是这个作用。就是用next函数调用时,返回的结果中value值就是yield后面跟的数据
function* genFunc() {
yield 3;
}
var g = genFunc();
console.log(g.next());//Object {value: 3, done: false}
2)接收数据,这个用途还没有看到过具体的例子,其实把yield赋值给一个变量就是这种用法。
function* genFunc() {
var b = 2 + (yield 3);
console.log(b);//7
}
var g = genFunc();
g.next()//这里不能省略,相当于让yield先产生数据
g.next(5);//yield接收数据
在往深了看一下,生产数据起到数据生产者的作用,接收数据起到数据消费者的作用。可以看出yield能衍生出很复杂的用法,以后的文章中在详细介绍。
生成器还有一个用法是可以有返回值的,生成器的返回值作为done为true时的value值:
function *foo() {
yield 1;
return 4;
}
var g = foo();
console.log(g.next());//Object {value: 1, done: false}
console.log(g.next());//Object {value: 4, done: true}
*以上全部代码在Chrome 48下通过测试