Generator函数运行后会返回一个遍历器对象。
此篇文章仅简单介绍一下,不会有任何复杂例子,详情建议阅读阮一峰<<ES6入门>>Generator 函数的语法。
Generator函数结构及运行
函数结构三个注意点:
function关键字后面的*号。- 内部的
yield表达式。 return语句可有可无,没有则返回undefined。
如下:
function* gen() {
yield 1;
yield 2;
yield 3;
return 4;
}
运行Generator函数:
- 选类似普通函数运行一次,会生成遍历器。
- 后续运行遍历器的
next()方法,每次会返回{ value: ..., done: [false|true] }对象。 - 如果
done: false表示遍历未结束,done: true表示遍历结束。 - 如果遍历结束后续再调用
next()方法将一直返回{ value: undefined, done: true }。
let g = gen();
g.next(); // { value: 1, done: false }
g.next(); // { value: 2, done: false }
g.next(); // { value: 3, done: false }
g.next(); // { value: 4, done: true }
g.next(); // { value: undefined, done: true }
在运行过程中,除了第一次之外的后续next()方法可以传入值。
function* gen() {
let a = yield 1;
console.log(a);
yield 2;
}
let g = gen();
g.next(); // { value: 1, done: false }
g.next(10);
// 10
// { value: 2, done: false }
g.next(); // { value: undefined, done: true }
如果Generator函数是某个对象的属性,记得前面的*号。
let obj = {
* gen() {
yield 1;
}
}
Generator原型方法
Generator.prototype.throw()
这个throw方法可在函数体外抛出错误,然后在函数体内捕获。
function* gen() {
try {
yield 1;
} catch(e) {
console.log(e);
}
yield 2;
}
let g = gen();
// 下面的next()记得一定要运行一次,否则只能被外部捕获
g.next(); // { value: 1, done: false }
g.throw('generator error 1');
// generator error 1
// { value: 2, done: false }
g.next(); // { value: undefined, done: true }
Generator.prototype.throw()注意点:
- 一个
try...catch语句中只能捕获一次错误,如果连续抛出多次错误,只会捕获到第一次。 - 记得要先运行第一次
next()方法,否则错误只能在函数体外捕获。 - 在体外抛出错误后,如果被捕获,会附带执行一次
next()方法,不影响下一次遍历。 - 注意
throw语句与Generator.prototype.throw方法不要混淆。 Generator函数体内抛出的错误,可以被函数体外的try...catch捕获。- 一旦
Generator执行过程抛出错误没有被内部捕获,此后调用next()方法,将一直返回{ value: undefined, done: true }。
Generator.prototype.return()
返回给定的值,并且终结遍历。
function* gen() {
yield 1;
yield 2;
yield 3;
}
let g = gen();
g.next(); // { value: 1, done: false }
g.return(10); // { value: 10, done: true }
g.next(); // { value: undefined, done: true }
next()、throw()、return()共同点
作用都是让Generator函数恢复执行,并且使用不同的语句替换yield表达式。
next(),替换为对应传入的值,没有传入值则返回undefined。throw(),替换为throw语句。return(),替换为return语句。
yield* 表达式
Generator函数体内支持嵌套其他Generator函数,内部会自行遍历,无需手动再遍历。
注意:如果嵌套的
Generator函数有返回值,那么在内部必须使用一个变量来存储才可以获取到返回值。
function* gen1() {
yield 3;
yield 4;
return 'gen1';
}
function* gen2() {
yield 1;
yield 2;
let gen1Value = yield* gen1();
console.log(gen1Value);
yield 5;
}
let g2 = gen2();
g2.next(); // { value: 1; done: false }
g2.next(); // { value: 2; done: false }
g2.next(); // { value: 3; done: false }
g2.next(); // { value: 4; done: false }
g2.next();
// gen1
// { value: 5; done: false }
g2.next(); // { value: undefined, done: true }
Generator返回的遍历器
Generator函数返回的是一个遍历器,支持下面的操作:
for...of遍历。- 扩展运算符
...。 - 解构赋值。
Array.from()方法。
for...of遍历
function* gen() {
yield 1;
yield 2;
yield 3;
}
for(let i of gen()) {
console.log(i);
}
// 1
// 2
// 3
扩展运算符...
function* gen() {
yield 1;
yield 2;
yield 3;
}
let a = [...gen()];
// [1, 2, 3]
解构赋值
function* gen() {
yield 1;
yield 2;
yield 3;
}
let [a, b, c] = [...gen()];
a; // 1
b; // 2
c; // 3
let { 0: x, 1: y, 2: z } = [...gen()];
x; // 1
y; // 2
z; // 3
Array.from()
function* gen() {
yield 1;
yield 2;
yield 3;
}
let a = Array.from(gen());
a; // [1, 2, 3]
小结
Generator函数主要几个最基本点:
function关键字后面的*号。- 函数内部的
yield语句。 - 函数内部用于嵌套其他
Generator函数的yield*语句。 - 函数需要先运行一次后才会返回遍历器,才可以后续使用
next()方法。 Generator.prototype.throw()。Generator.prototype.return()。