ES6之Generator 函数(生成器)的语法

一、简介

  • 概念:
    调用 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属性为truefor...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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容