Generator函数是什么
- 语法上:首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
- 形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)
例子:
function* testGenerator () {
yield "hello";
yield "world";
return "end"
}
const test = testGenerator()
console.log(test);
console.log(test.next()); // {value: "hello", done: false}
console.log(test.next()); // {value: "world", done: false}
console.log(test.next()); // {value: "end", done: true}
console.log(test.next()); // {value: undefined, done: true}
与 Iterator 接口的关系
任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。
g[Symbol.iterator]() === g //true
与 for...of...的关系
for...of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。
function* foo() {
yield 1;
yield 2;
yield 3;
}
for (let v of foo()) {
console.log(v);
}
// 1,2,3
Generator.prototype.throw()
Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
const gFunc = function* () {
try {
yield "yield"
} catch (e) {
console.log("内部捕获:", e);
}
}
const g = gFunc()
console.log(g.next());
try {
g.throw("233")
g.throw()
} catch (e) {
console.log("外部捕获:", e);
}
// {value: "yield", done: false}
// 内部捕获: 233
// 外部捕获: undefined
之所以第二次走的是外部捕获,因为第一次内部已经抛出了异常,内部已经判定执行异常了,所以第二次走的是全局的 error 监听
Generator.prototype.return()
Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
//如果return方法调用时,不提供参数,则返回值的value属性为undefined
g.next() // { value: 1, done: false }
g.return() // { value: undefined, done: true }
如果 Generator 函数内部有try...finally代码块,且正在执行try代码块,那么return方法会导致立刻进入finally代码块,执行完以后,整个函数才会结束。(即执行完finally代码块后才会执行 return)
<script>
function* numbers() {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var g = numbers();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.return(7)); // { value: 4, done: false }
console.log(g.next()); // { value: 5, done: false }
console.log(g.next()); // { value: 7, done: true }
</script>
另外 for...of 也可以遍历 generator,不用手动next(),for...of循环本质上就是调用这个接口产生的遍历器。
网友评论