ECMAScript/ES6生成器

ECMAScript/ES6生成器

生成器(或生成器功能)是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

注意:生成器函数无法使用箭头函数表示。