一、简介
- 概念:
调用 Generator 函数后,该函数并不执行,返回一个指向内部状态的指针对象即遍历器对象。形式上,Generator 函数是一个普通函数,但是有两个特征:1)function关键字与函数名之间有一个星号;2)函数体内部使用yield表达式,定义不同的内部状态。Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
- yield 表达式:
遍历器对象的next
方法的运行逻辑如下:
1)遇到yield
表达式,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值;
2)下一次调用next
方法时,再继续往下执行,直到遇到下一个yield
表达式;
3)一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值;
4)如该函数没有return语句,则返回的对象的value属性值为undefined。
yield
表达式只能用在 Generator 函数里面,用在其他地方都会报错
二、next()、throw()、return()方法
next()
、throw()
、return()
这三个方法本质上是同一件事,它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield
表达式。
-
next()
:该方法若是带参数就将上一个yield表达式替换成该参数,若不带参数就替换成undefined
const g = function* (x, y) {
let result = yield x + y;
return result;
};
const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}
gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;
-
throw()
:将yield
表达式替换成一个throw语句。
gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));
- return():将yield表达式替换成一个return语句。
gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
三、for...of 循环
for...of
循环可以自动遍历 Generator 函数运行时生成的Iterator
对象,且此时不再需要调用next
方法。注意,一旦next
方法的返回对象的done
属性为true
,for...of
循环就会中止,且不包含该返回对象
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
四、yield* 表达式
用于在一个 Generator 函数里面执行另一个 Generator 函数
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
function* foo() {
yield 'a';
yield 'b';
}
/*等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
*/
for (let v of bar()){
console.log(v);
}
// "x"
// "a"
// "b"
// "y"
五、作为对象属性的 Generator 函数
let obj = {
* myGeneratorMethod() {
//···
}
};
/*等同于
let obj = {
myGeneratorMethod: function* () {
// ···
}
};
*/
六、Generator 函数的this
Generator 函数返回的总是遍历器对象,不是this对象。
问题:
1)Generator 函数在this对象上面添加了一个属性,但是该函数的实例对象拿不到这个属性
2)Generator 函数不能跟new
命令一起用,会报错
解决:首先,使用call方法将 Generator 函数的this绑定成自身的protoytype,再将 Generator 函数改成构造函数,就可以对它执行new命令了
function* gen() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
function F() {
return gen.call(gen.prototype);
}
var f = new F();
f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}
f.a // 1
f.b // 2
f.c // 3