一、function*

function*这种声明方式会定义一个生成器函数(generator function),它返回一个Generator(生成器)对象。

生成器函数在执行时能暂停,之后又能从暂停处继续执行。调用生成器函数并不会马上执行函数中的语句,而是返回一个生成器的迭代器(iterator)对象。

每次调用迭代器的next()方法时,函数中的语句会从开始(首次调用next())或前一个yield执行到下一个yield的位置为止,yield后紧跟迭代器要返回的值。(如果使用的是yield*,则表示暂停当前生成器的执行并将执行权移交给另一个生成器函数。)

next()方法返回一个包含valuedone属性的对象,其中value表示本次yield表达式的返回值,done为布尔类型,表示生成器后续是否还有yield语句(即生成器函数是否执行完成并返回)。调用next()方法时,如果传入了参数,那么这个参数会作为前一条执行的yield语句的返回值。

如果在生成器函数中显示return时,此时会立即将生成器变为完成状态(即next()方法返回的对象的done属性值为true)。如果return语句后有值,则该值会作为next()方法返回的对象的value属性值。

注意:生成器函数不能当做构造函数使用()。

1、function*声明

  • 语法
function* name([param1[, param2[, ...paramN]]]){
	
}

其中name为函数名,param为传递给函数的参数,一个函数最多可以有255个参数。

  • 示例一
function* test(){
	yield 10;
	let y = yield 'foo';
	console.log(`y=${y}`);//y=5
	yield y;
	console.log(`y=${y}`);//y=5
	return 'hello world!';
	yield 'unreachable';//不会被执行
}

let gen = test();
//执行yield 10,返回10
console.log(gen.next());//{value: 10, done: false}
//执行yield 'foo',返回'foo'
console.log(gen.next());//{value: "foo", done: false}
//将5作为前一个`yield`语句的返回值,即执行let y = 5,返回5
console.log(gen.next(5));//{value: 5, done: false}
//执行完毕
console.log(gen.next());//{value: "hello world!", done: true}
y=5
{value: 5, done: false}
y=5
  • 示例二
function* genFnTest(){
	let first = yield 1;
	let second = yield first + 2;
	yield second + 3;
}

let gen = genFnTest();
console.log(gen.next());//{value: 1, done: false}
console.log(gen.next(4));//{value: 6, done: false}
console.log(gen.next(5));//{value: 8, done: false}
console.log(gen.next());//{value: undefined, done: true}
  • 示例三
function* foo(){
	yield 'a';
	yield 'b';
	yield 'c';
}

let str = '';
for(let val of foo()){
	str += val;
}
console.log(str);//abc
  • 示例四
function* idMaker(){
	let index = 0;
	while(index < 3){
		yield index++;
	}
}

let gen = idMaker();
console.log(gen.next());//{value: 0, done: false}
console.log(gen.next());//{value: 1, done: false}
console.log(gen.next());//{value: 2, done: false}
console.log(gen.next());//{value: undefined, done: true}

带参数的生成器:

function* idMaker(){
	let index = arguments[0] | 0;
	let max = index + 3;
	while(index < max){
		yield index++;
	}
}

let gen = idMaker(5);
console.log(gen.next());//{value: 5, done: false}
console.log(gen.next());//{value: 6, done: false}
console.log(gen.next());//{value: 7, done: false}
console.log(gen.next());//{value: undefined, done: true}
  • 示例五

将多维数组转为一维数组:

function* iterArr(arr){
	if(Array.isArray(arr)){
		for(let i = 0; i < arr.length; i++){
			yield * iterArr(arr[i]);
		}
	}else{
		yield arr;
	}
}
//使用for-of
let arr = ['a', ['b', 'c'], ['d', 'e']];
let ret = [];
for(let x of iterArr(arr)){
	ret.push(x);
}
console.log(ret);//["a", "b", "c", "d", "e"]
//直接将迭代器展开
arr = ['a', ['b',[ 'c', ['d', 'e']]]];
let gen = iterArr(arr);
ret = [...gen];
console.log(ret);//["a", "b", "c", "d", "e"]

2、function*表达式

  • 语法
function* [name]([param1[, param2[, ...paramN]]]){
	
}

function*声明类似,其中函数名name在声明匿名函数时可以省略。

  • 示例
var x = function*(y){
	yield y * y;
}

二、yieldyield*

1、yield

yield关键字用来暂停或恢复一个生成器函数。

  • 语法
[rv] = yield [expression];

如果省略expression,则返回undefined

  • 说明

    生成器函数执行遇到yield表达式时,函数代码将被暂停,直到生成器的next()方法被调用。每次调用生成器的next()方法时,生成器函数都会恢复执行,直到达到以下某个值:

    • 遇到yield语句

      导致生成器再次暂停并返回生成器的新值

    • 遇到throw语句

      当抛出异常时,生成器完全停止执行,在调用者中继续执行,同正常情况下的异常抛出

    • 遇到return语句

      生成器执行结束,将IteratorResult返回给调用者,返回对象的value属性值为return的值,done属性值为true

    • 到达生成器函数的结尾(无return)

      生成器执行结束,将IteratorResult返回给调用者,返回对象的value属性值为undefineddone属性值为true

2、yield*

yield*表达式用于代理另一个生成器或可迭代对象。(用来在一个生成器函数中执行另一个生成器函数,直接调用是没用的。)

  • 语法
yield* [[expression]];

其中expression表达式须返回一个可迭代的表达式。

yield*表达式本身的值是当迭代器关闭时(done属性值为true时)返回的值。

  • 示例一
function* generator(i){
	yield i + 1;
	yield i + 2;
	yield i + 3;
}

function* anotherGenerator(i){
	yield i;
	yield* generator(i);//移交执行权
	yield i + 10;
}

let gen = anotherGenerator(10);
console.log(gen.next());//{value: 10, done: false}
console.log(gen.next());//{value: 11, done: false}
console.log(gen.next());//{value: 12, done: false}
console.log(gen.next());//{value: 13, done: false}
console.log(gen.next());//{value: 20, done: false}
console.log(gen.next());//{value: undefined, done: true}
  • 示例二

yield*

function* generator(){
	yield* [1, 2];
	yield* "34";
	yield* arguments;
}

let gen = generator(5, 6);
console.log(gen.next());//{value: 1, done: false}
console.log(gen.next());//{value: 2, done: false}
console.log(gen.next());//{value: "3", done: false}
console.log(gen.next());//{value: "4", done: false}
console.log(gen.next());//{value: 5, done: false}
console.log(gen.next());//{value: 6, done: false}
console.log(gen.next());//{value: undefined, done: true}
  • 示例三
function* generator(){
	yield* [1, 2, 3];
	return 'foo';
}

let ret;

function* anotherGenerator(){
	ret = yield* generator();
}

let gen = anotherGenerator();
console.log(gen.next());//{value: 1, done: false}
console.log(gen.next());//{value: 2, done: false}
console.log(gen.next());//{value: 3, done: false}
console.log(ret);//undefined
console.log(gen.next());//{value: undefined, done: true}
console.log(ret);//foo

三、生成器方法

1、next()

next()方法返回一个包含valuedone属性的对象。

  • 语法
gen.next(value)

其中value为向生成器传递的值。

  • 示例
function* gen(){
	yield 1;
	let ret = yield 2;
	return ret;
}

let g = gen();
console.log(g.next());//{value: 1, done: false}
console.log(g.next());//{value: 2, done: false}
console.log(g.next('hello world'));//{value: "hello world", done: true}

2、return()

返回给定的值并结束生成器。

  • 语法
gen.return(value)

其中value为需要返回的值。

如果对已完成的生成器调用return(value),生成器仍保持完成状态。如果return()方法没有参数,则返回对象与next()方法返回相同;否则,将方法参数设置为返回对象的value属性值。

  • 示例
function* gen(){
	yield 1;
	yield 2;
	yield 3;
} 

let g = gen();
console.log(g.next());//{value: 1, done: false}
console.log(g.return('foo'));//{value: "foo", done: true}
console.log(g.next());//{value: undefined, done: true}
console.log(g.return());//{value: undefined, done: true}
console.log(g.return('bar'));//{value: "bar", done: true}

3、throw()

此方法向生成器抛出异常,并恢复生成器的执行,返回带有valuedone属性的对象。

  • 语法
gen.throw(exception)

其中exception为抛出的异常,建议抛出Error对象的实例。

  • 示例一
function* gen(){
	try{
		yield 'foo';
		yield 'bar';
	}catch(e){
		console.log('Error caught!');
	}
	yield 'foo bar';
}

let g = gen();
console.log(g.next());
console.log(g.throw(new Error('Something went wrong!')));

输出:

{value: "foo", done: false}
Error caught!
{value: "foo bar", done: false}
  • 示例二
function* gen(){
	let x = 0;
	while(x < 4){
		try{
			yield x++;
		}catch(e){
			console.log(`Caughted Error: ${e.message}`);
		}
	}
}

let g = gen();
try{
	console.log(g.next());//
	console.log(g.throw(new Error('wrong!')));//
	console.log(g.next());//
	console.log(g.throw(new Error('error!')));//
	console.log(g.next());//
	console.log(g.throw(new Error('xxx!')));//
	console.log('Will not be executed');
}catch(e){
	console.log('out caught...', e.message);
}
console.log('finish');

输出:

{value: 0, done: false}

Caughted Error: wrong!
{value: 1, done: false}

{value: 2, done: false}

Caughted Error: error!
{value: 3, done: false}

{value: undefined, done: true}
out caught... xxx!

finish
附: