Generator(生成器)

◼ 生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。
    平时我们会编写很多的函数,这些函数终止的条件通常是返回值或者发生了异常。
◼ 生成器函数也是一个函数,但是和普通的函数有一些区别:
    首先,生成器函数需要在function的后面加一个符号:*
    其次,生成器函数可以通过yield关键字来控制函数的执行流程:
    最后,生成器函数的返回值是一个Generator(生成器):
        ✓ 生成器事实上是一种特殊的迭代器;
        ✓ MDN:Instead, they return a special type of iterator, called a Generator.

生成器函数的使用:

  /*生成器函数特点:
  1.function后面会加上符合:*  function*
  2.代码的执行可以被yield控制
  3.生成器函数在执行时,返回一个生成器对象
    *要想执行函数内部代码,需要生成器对象调用他的next操作
    *当遇到yield时就会中断执行
    */
    function* foo(){
      console.log("11111")
      console.log("22222")
      yield console.log("aaaaa")
      console.log("33333")
      console.log("44444")
      yield
      console.log("55555")
      console.log("66666")
    }
    // 调用生成器函数会返回一个生成器对象
    const generator = foo()
    // 调用next方法
    generator.next()
    generator.next()
    generator.next()

生成器传递参数–next函数

 ◼ 函数既然可以暂停来分段执行,那么函数应该是可以传递参数的,我们是否可以给每个分段来传递参数呢?
    答案是可以的;
    我们在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值;
    注意:也就是说我们是为本次的函数代码块执行提供了一个值;
   function* foo(name1){
  console.log("执行内部代码11111",name1)
  console.log("执行内部代码1111122222",name1)
 const name2 = yield "aaaa"
  console.log("执行内部代码1111133333",name2)
  console.log("执行内部代码1111144444",name2)
 const name3 = yield "bbbb"
  console.log("执行内部代码1111155555",name3)
  console.log("执行内部代码1111166666",name3)
}
// 调用生成器函数会返回一个生成器对象
const generator = foo("第一次调用next")
// 调用next方法-->拿返回值
// console.log(generator.next())//{value: 'aaaa', done: false}
// console.log(generator.next())//{value: 'bbbb', done: false}
// console.log(generator.next())//{value: undefined, done: true}
// // 再中间位置直接return 结果-->拿返回值
// console.log(generator.next())//{value: 'aaaa', done: false}
// console.log(generator.next())//{value: 'bbbb', done: true}
// console.log(generator.next())//{value: undefined, done: true}
//4.给函数每次执行传入参数
console.log(generator.next())//{value: 'aaaa', done: false} -->执行内部代码11111 第一次调用next
console.log(generator.next("第二次调用next"))//{value: 'aaaa', done: false} -->执行内部代码1111133333 第二次调用next
console.log(generator.next("第三次调用next"))//{value: undefined, done: true}-->执行内部代码1111166666 第三次调用next

生成器提前结束–return函数

◼ 还有一个可以给生成器函数传递参数的方法是通过return函数:
    return传值后这个生成器函数就会结束,之后调用next不会继续生成值了;
    function* foo(name1){
      console.log("执行内部代码11111",name1)
      console.log("执行内部代码1111122222",name1)
    const name2 = yield "aaaa"
      console.log("执行内部代码1111133333",name2)
      console.log("执行内部代码1111144444",name2)
    const name3 = yield "bbbb"
      console.log("执行内部代码1111155555",name3)
      console.log("执行内部代码1111166666",name3)
      yield
      console.log("最后一次执行")
      return undefined
    }
    //1.generator.return()提前结束
    const generator = foo("nex1")
    // console.log(generator.next())
    // console.log(generator.return("next2"))
    // console.log("-----------------")
    // console.log(generator.next("next3"))
    // console.log(generator.next("next4"))

生成器抛出异常–throw函数

    ◼ 除了给生成器函数内部传递参数之外,也可以给生成器函数内部抛出异常:
      抛出异常后我们可以在生成器函数中捕获异常;
      但是在catch语句中不能继续yield新的值了,但是可以在catch语句外使用yield继续中断函数的执行;
      function* foo(){
        console.log("函数开始执行~")
        try{
          yield "hdc"
        }catch(err){
          console.log("内部异常捕获:",err)
        }
        yield 222
        console.log("函数执行结束")
      }

生成器替代迭代器

    ◼ 我们发现生成器是一种特殊的迭代器,那么在某些情况下我们可以使用生成器来替代迭代器:
     const names = ["aaa","bbb","ccc"]
      const nums = [66,88,555,111]
      
      function* createArrayIterator(arr){
        for (let i = 0;i<arr.length;i++){
          yield arr[i]
        }
      }
      const namesIterator = createArrayIterator(names)
      console.log(namesIterator.next())
      console.log(namesIterator.next())
      console.log(namesIterator.next())
      console.log(namesIterator.next())

      const numsIterator = createArrayIterator(nums)

事实上我们还可以使用yield*来生产一个可迭代对象:

 这个时候相当于是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值;
  yield*必须放到生成器函数中
const names = ["aaa","bbb","ccc"]
const nums = [66,88,555,111]

function* createArrayIterator(arr){
  for (let i = 0;i<arr.length;i++){
    yield* arr
  }
}
const namesIterator =createArrayIterator(names)
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())

自定义类迭代–生成器实现

  class ClassRoom{
    constructor(address,name,students){
      this.address = address
      this.name = name
      this.students = students
    }
    push(student){
      this.students.push(student)
    }
    *[Symbol.iterator](){
      yield* this.students
    }
  }
const classRoom1 = new ClassRoom("dhdhd","ddddd",["aaaa","bbbb","vvvvv"])
const PIteratro = classRoom1[Symbol.iterator]()
console.log(PIteratro.next())
console.log(PIteratro.next())
console.log(PIteratro.next())
console.log(PIteratro.next())
posted @ 2024-10-21 13:56  韩德才  阅读(19)  评论(0编辑  收藏  举报