首页 > 代码库 > Generator 函数学习笔记

Generator 函数学习笔记

// 使用 function* 定义一个 generator 函数
function* helloWorldGenerator() {
  yield ‘hello‘;  // yield 关键字作为暂停的点
  yield ‘world‘;
  return ‘ending‘;
}

var hw = helloWorldGenerator();  // 执行 generator 函数,返回一个遍历器对象。而这时,这个函数内的代码并不会执行。
// 调用遍历器对象的 next 方法,执行函数内的代码,执行到下一个 yield 的位置,并暂停执行
hw.next()
// { value: ‘hello‘, done: false }  value 是 yield 后面跟的表达式的值,done 是 genertator 函数结束状态

// 再次调用 next,执行到下一个 yield 位置
hw.next()
// { value: ‘world‘, done: false }

// 执行结束,value 值为 return 的值,没有 return 则为 undefined(函数没 return 返回 undefined),done 变为 true
hw.next()
// { value: ‘ending‘, done: true }

// 还可以无限次调用 next,但是都返回相同的对象
hw.next()
// { value: undefined, done: true }

yield 不能用在普通函数中:

var flat = function* (a) {
  // forEach 方法是个普通函数,在里面使用了 yield 会报错。解决方法是改为 for 循环
  a.forEach(function (item) {
    if (typeof item !== ‘number‘) {
      yield* flat(item);
    } else {
      yield item;
    }
  }
};

yield语句如果用在一个表达式之中,必须放在圆括号里面。

console.log(‘Hello‘ + yield); // SyntaxError
console.log(‘Hello‘ + yield 123); // SyntaxError

console.log(‘Hello‘ + (yield)); // OK
console.log(‘Hello‘ + (yield 123)); // OK

 

next方法的参数

function* foo(x) {
  var y = 2 * (yield (x + 1));  // yield 语句在表达式中,需要将 yield 语句括起来,否则报错
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }  调用第一次 next 开始执行,得到第一个 yield 的返回值 6。由于 next 参数为上一个 yield 语句的值,所以第一个 next 传入参数没有意义
b.next(12) // { value:8, done:false }  调用 next 方法时注入了数据,作为上一个 yield 语句的值,得到 var y = 2 * 12
b.next(13) // { value:42, done:true }  得到 var z = 13

for...of循环

 for...of循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法。

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  这里需要注意,一旦next方法的返回对象的done属性为truefor...of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for...of循环之中。

 原生的JavaScript对象没有遍历接口,无法使用for...of循环,通过Generator函数为它加上这个接口,就可以用了。

// 第一种方法
function* objectEntries(obj) {
  let propKeys = Reflect.ownKeys(obj);

  for (let propKey of propKeys) {
    yield [propKey, obj[propKey]];
  }
}

let jane = { first: ‘Jane‘, last: ‘Doe‘ };

for (let [key, value] of objectEntries(jane)) {
  console.log(`${key}: ${value}`);
}

// 第二种方法
function* objectEntries() {
  let propKeys = Object.keys(this);

  for (let propKey of propKeys) {
    yield [propKey, this[propKey]];
  }
}

let jane = { first: ‘Jane‘, last: ‘Doe‘ };

jane[Symbol.iterator] = objectEntries;

for (let [key, value] of jane) {
  console.log(`${key}: ${value}`);
}

 

Generator 函数学习笔记