Generator

2020-08-19  本文已影响0人  jluemmmm

Generator函数是一个状态机,封装了多个内部状态。同时Generator还是一个遍历器对象生成函数,执行Generator函数会返回一个遍历器对象,返回的遍历器对象可以依次遍历Generator函数内部的每一个状态。其特征如下:

function* helloWorld() {
  yield 'hello'
  yield 'world'
  return 'ending'
}                                                                                                                                                                                                                                                                                                                                                                                                                                                
var hw = helloWorld()
hw.next()
// {value: "hello", done: false}
hw.next()
// {value: "world", done: false}
hw.next()
// {value: "ending", done: true}
hw.next()
// {value: undefined, done: true}

调用Generator函数后,返回的是一个指向内部状态的指针对象。调用遍历器对象的next方法,使得指针下移一个状态,内部指针从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式。

遍历器对象的 next 方法运行逻辑:

  1. 遇到 yield 语句暂停执行后面的操作,并将紧跟在 yield 后面的表达式的值作为返回的对象的 value 属性值
  2. 下一次调用 next 方法时再继续往下执行,直到遇到下一条yield语句
  3. 如果没有再遇到新的 yield语句,一直运行到函数结束,直到 return 语句为止,并将return 语句后面的表达式的值作为返回对象的 value 属性值
  4. 如果该函数没有 return 语句,返回对象的value 属性值为 undefined

yield 语句本身没有返回值,next 方法可以带有一个参数,该参数会被当作上一条 yield 语句的返回值

function * foo(x) {
  var y = 2 * ( yield (x + 1) )
  var z = yield (y / 3)
  return (x + y + z)
}

// yield 语句的值就是调用 next 方法的返回值

var a = foo(5)
a.next() // 6
a.next() // NaN :------ next 方法不带参数, y 的值为 2 * undefined
a.next() // NaN 

var b = foo(5) // 如果调用方法传入 next 值, next 传入的值会被当作上一条 yield 语句的返回值
b.next() // 6 ------- y: 12
b.next(12) // 8 ------y: 24, z: 4
b.next(13) // x: 5; y: 24; z: 13 ------- 42

对象的Symbol.interator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象,由于Generator函数就是遍历器生成函数,可以把Generator函数赋给Symbol.iterator属性,从而使得该对象具有Interator接口。

var iter = {};
iter[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
[...iter]

for...of 循环可以自动遍历 Generator 函数生成的 Iterator 对象,不再需要调用 next 方法。当 next 方法返回的对象的 done 属性为 true 时,for...of 循环会终止,且不包含该返回对象,return 语句返回值不会出现在 for...of 循环中

对象不具备原生 Iterator 接口,可以自行定义实现

let jane = {
  first: 'Jane',
  last: 'Doe'
}

function * objEnt() {
  let propKeys = Object.keys(this)
  for(let key of propKeys) {
    yield [key, this[key]]
  }
}

jane[Symbol.iterator] = objEnt

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

for...of 循环,扩展运算符,解构赋值和Array.from 方法内部调用的都是遍历器接口,可以将 Generator 函数返回的 Iterator 对象作为参数

上一篇 下一篇

猜你喜欢

热点阅读