ES6 Generator

发布时间 2023-11-29 18:09:13作者: 我是小凳子

Generator

Generator 函数是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,返回的遍历器对象可以依次遍历 Generator 函数内部的每一个状态。

函数特征:1. function 关键字与函数名之间有一个星号。2. 函数体内部使用 yield 表达式定义不同的内部状态。

function *hello() {
  yield "hello"
  yield "world"

  return "ending"
}

var h = hello()

h.next() // { value: 'hello', done: false }
h.next() // { value: 'world', done: false }
h.next() // { value: 'ending', done: false } // 如果没有 return 的话,返回 { value: undefined, done: true }
h.next() // { value: undefined, done: true }

Generator 函数调用方式同普通函数,不同的是:调用 Generator 函数后,该函数不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象(即 遍历器对象)。

yield 表达式是暂停执行的标记,而 next() 可以恢复执行。

Generator 函数执行后,返回一个遍历器对象。该对象本身也具有Symbol.iterator属性,执行后返回自身。

next() 、throw() 、return() 共同点:替换 yield 表达式。

yield 表达式

遇到 yield 表达式,就暂停执行后边的操作,并将紧跟在 yield 后的那个表达式的值作为返回的对象 value 属性值。

yield 表达式只能在 Generator 函数中。

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

function *fn {
  // console.log('Hi,'+ yield) // 会报错
  console.log("Hi", + (yield)) // 运行OK

  // console.log('Hi,'+ yield 123) // 会报错
  console.log("Hi", + (yield 123)) // 运行OK
}

yield 表达式用作函数参数或者放在赋值表达式的右边,可以不加括号。

function *fn {
  foo(yield 'a', yield 'b') // 运行OK
  
  let input = yield  // 运行OK
}

next()

yield 表达式本身没有返回值,或者是总是返回 undefined , next() 可以带一个参数,这个参数作为上一个 yield 表达式的返回值。

function *f() {
  for(var i=0; true; i++) {
    var reset = yield i
    if(reset) {i = -1}
  }
}
var g = f()
console.log(g.next()) // { value: 0, done: false }
console.log(g.next()) // { value: 1, done: false }
console.log(g.next(true)) // { value: 0, done: false }

next(true) => reset = true => i = -1 => value: 0

第一次执行 next() 会忽略参数。

Generator.prototype.throw()

可以接受一个参数,会被 catch 语句接收:it.throw(new Error('出错啦'))

如果 Generator 函数内部没有部署 try...catch 代码块,那么throw方法抛出的错误,将被外部 try...catch 代码块捕获。

throw 方法抛出的错误要被内部捕获,前提是必须至少执行过一次 next 方法。throw方法被捕获以后,会附带执行一次 next 方法。

throw 命令只能被函数体外的 catch 语句捕获:throw new Error('a')

一旦 Generator 执行过程中抛出错误,且没有被内部捕获,就不会再执行下去了。

Generator.prototype.return()

可以返回指定的值,并终结遍历 Generator 函数。

如果 Generator 函数内部有 try...finally 代码块,且正在执行 try 代码块,那么 return() 方法会导致立刻进入 finally 代码块,执行完以后,整个函数才会结束。

yield* 表达式 在 Generator 函数中执行另一个 Generator 函数

Generator 函数的 this

function * g() {
  this.a = 11
}

let obj = g()
obj.next()
obj.a // undefined (因为 g 返回的总是 遍历器对象,不是 this 对象)

Generator 函数也不能跟 new 命令一起用,会报错。