参考:Generator 函数的含义与用法
ES6 Generator
1.基本用法
Generator函数两个特征:
- 函数名与function之间有个
*
- 函数内部使用yield表达式
每次调用next方法,返回一个对象,包含value和done,value的值即yield后面表达式的值
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
2.yield
Generator函数内部,找两个关键字: yield
和 return
注意:y = yield 1 + 1; 此时y是undefined,并非2
遇到yield就暂停后面的操作,并把紧跟在yield后面的表达式的值,作为返回对象的value值属性。并且每次执行next才会去找yield,依次往下找,找不到yield则找return;
3.next方法的参数
yield表达式本身没有返回值,或者说总是返回 undefined
,我们看下面这个例子
function* helloWorldGenerator() {
var y = yield 1 + 1
return y
}
let hw = helloWorldGenerator()
console.log(hw.next()) // { value: 2, done: false }
console.log(hw.next()) // { value: undefined, done: true }
第一个next返回对象的value是 表达式 1+1
的值,但整个 yield 1+1
是没有返回值的,所以最后y为undefined就结束了
那怎么改变这种情况呢?next方法可以带入一个参数,这个参数就是上一个yield表达式的值;看下面这个例子
function* f() {
for(var i = 0; true; i++) {
var reset = yield i;
if(reset) { i = -1; }
}
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }
对于前两个g.next方法,由于没有传参,所以reset都是undefined,函数执行下去,都会走i++,所以第一次和第二次比value都在+1。当第三个next执行时,传了参数true,此时上一个yield表达式返回true, reset为true, 函数往下执行;i = -1,然后走for循环 i++; 所以最后i = 0
4.循环遍历
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
for of 循环可以自动遍历Generator函数运行时生成的Iterator对象,此时无需调用next方法
循环会在next方法返回的对象的done属性为true时终止,并且结果不包含改对象的value;所以上面最终打印结果没有6
Array.from和扩展符
除了for…of循环以外,扩展运算符(…)、解构赋值和Array.from方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数。
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
// 扩展运算符
[...numbers()] // [1, 2]
// Array.from 方法
Array.from(numbers()) // [1, 2]
5.next()、throw()、return()方法
next()、throw()、return()这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式。
next()是将yield表达式替换成一个值,前面有提到,即将参数作为上一个yield表达式的返回值;这里就不举例
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;
6.generator函数的this
function* g() {}
g.prototype.hello = function () {
return 'hi!';
};
let obj = g();
obj instanceof g // true
obj.hello() // 'hi!'
注意:generator函数实例化对象,不能使用关键字new!!!
function* g() {
this.a = 11;
}
let obj = g();
obj.next();
obj.a // undefined
Generator函数在this对象上添加一个属性a,但是obj对象拿不到