ECMAScript/ES6生成器
生成器(或生成器功能)是ES6中引入的新概念。 它提供了一种处理迭代器和函数的新方式。
ES6生成器是另一种函数,可以在中间暂停一次或多次,然后可以恢复。 调用标准函数时,控件将一直处于被调用函数的状态,直到返回为止,但是ES6中的生成器允许调用者函数控制被调用函数的执行。
生成器与常规函数相同,除了几个方面不相同:
- 当生成器被调用时,它不会运行其代码。 而是返回一个特殊对象,称为“生成器对象”,用于管理执行。
- 生成器函数可以随时将控制权返回(或让步)给调用者。
- 与常规函数不同,生成器可以根据需要一个接一个地返回(或产生)多个值。
1.语法
生成器函数的语法几乎与常规函数相同。 唯一的实际区别是,生成器函数通过在function
关键字后缀星号(*
)来表示。
在以下语法中,我们将演示一些定义生成器函数的有效方法:
function* mygenfun() // Valid
{
yield 1;
yield 2;
...
...
}
function *mygenfun() // Valid
{
yield 1;
yield 2;
...
...
}
function*mygenfun() // Valid
{
yield 1;
yield 2;
...
...
}
示例代码
function* gen()
{
yield 100;
yield;
yield 200;
}
// Calling the Generator Function
var mygen = gen();
console.log(mygen.next().value);
console.log(mygen.next().value);
console.log(mygen.next().value);
执行上面示例代码,得到一些输出结果:
100
undefined
200
2.yield语句
yield
语句将中止函数执行,并将一个值发送回调用方。 它保留了足够的状态,以使函数可以从中断处恢复。 恢复后,该函数将在上次运行yield
之后立即继续执行。 它可以产生一系列值。
3.next()方法
在上面的示例中,我们使用了next()
方法,这是生成器的主要方法。 当将next()
方法与参数一起调用时,它将恢复生成器函数的执行,并用next()
方法中的参数替换暂停执行的生成表达式。
next()
方法的结果始终是一个具有两个属性的对象:
value
: 它是yield
的值。done
: 它是一个布尔值,如果函数代码已完成,则为true
。 否则为false
。
在下面示例中,创建一个生成器函数并获取其产生的值。
示例代码
function* show() {
yield 100;
}
var gen = show(); //here 'gen' is a generator object
console.log(gen.next()); // { value: 100, done: false }
执行上面示例代码,得到以下结果:
{ value: 100, done: false }
4.生成器对象
生成器函数返回生成器对象。 生成器对象是生成器函数的实例,它既符合Iterable
接口又符合Iterator
接口。
可以通过调用next()
方法或在循环内使用生成器对象来使用生成器对象。生成器对象是一个迭代器;因此可以在for…of
循环或接受迭代的其他函数中使用。
在上面的next()
方法示例中,变量gen
是生成器对象。
5.生成器中的返回语句
return
用于将指定值发送回其调用方。它用于结束函数调用执行,并将结果返回给调用方。 在函数内,在return
语句之后定义的语句不会执行。 因此return
语句应该是函数的最后一条语句。
通过一个示例来了解生成器中的return
语句:
示例
function* myGen() {
yield 'First yield statement';
yield 'Second yield statement';
return 'Return statement';
yield 'Second yield statement';
}
let genobj = myGen();
console.log(genobj.next()); //returns {value: 'First yield statement', done: false}
console.log(genobj.next()); //returns {value: 'Second yield statement', done: false}
console.log(genobj.next()); //returns {value: 'Return statement', done: true}
console.log(genobj.next()); //returns {value: undefined, done: true}
执行上面示例代码,得到以下结果:
{ value: 'First yield statement', done: false }
{ value: 'Second yield statement', done: false }
{ value: 'Return statement', done: true }
{ value: undefined, done: true }
在上面的示例中,定义了一个生成器函数myGen()
,其中定义了四个语句,包括三个yield
语句和return
语句。 每当调用next()
方法时,函数都会继续执行,直到命中下一个yield
语句为止。
注意到第一个next()
方法如何返回:"First yield statement"
。 当第二次调用next()
方法时,它将恢复执行并返回"Second yield statement"
。 再次调用next()
方法后,该函数不再找到yield
语句并返回"Return statement"
。 但是当第四次调用next()
方法时,它将不考虑yield
语句,并且返回undefined
,因为它是在Return statement
之后编写的。
可以在上面示例的输出中看到,next()
方法在return
语句之后不考虑任何语句。
6.带有for…of循环的生成器函数
将for…of
循环与生成器函数一起使用会减少代码行。
示例代码
"use strict"
function* vowels() {
// here the asterisk marks this as a generator
yield 'X';
yield 'N';
yield 'T';
yield 'O';
yield 'R';
}
for(let alpha of vowels()) {
console.log(alpha);
}
执行上面示例代码,得到以下结果:
X
N
T
O
R
注意:生成器函数无法使用箭头函数表示。