Iterator-Generator详解

1 迭代器可迭代对象

2 原生的迭代器对象

3 自定义类的迭代器

4 生成器理解和作用

5 自定义生成器方案

6 异步处理方案解析

迭代器-JavaScript中迭代器(了解)

给某个数组专门添加一个迭代器的代码。

 const names = ["abc", "cba", "nba"]
    
    // 给数组names创建一个迭代器(迭代器: names的迭代器)
    let index = 0
    const namesIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (index < names.length) {
          return { done: false, value: names[index++] }
        } else {
          return { done: true }
        }
      }
    }

    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    // 数组nums
    const nums = [100, 24, 55, 66, 86]
    
    let indexNum = 0
    const numsIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (indexNum < nums.length) {
          return { done: false, value: nums[indexNum++] }
        } else {
          return { done: true }
        }
      }
    }

迭代器-为数组创建迭代器(了解)

给任意数组做的迭代器。

 const names = ["abc", "cba", "nba"]
    const nums = [100, 24, 55, 66, 86]

    // 封装一个函数
    function createArrayIterator(arr) {
      let index = 0
      return {
        next: function() {
          if (index < arr.length) {
            return { done: false, value: arr[index++] }
          } else {
            return { done: true }
          }
        }
      }
    }

    const namesIterator = createArrayIterator(names)
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    const numsIterator = createArrayIterator(nums)
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())

可迭代对象-创建可迭代对象(了解)

可迭代对象和迭代器是两个东西,迭代器是可迭代对象里面的方法,这样子的对象是可通过迭代器来迭代的,可以通过迭代来获取value值。

 // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
    const infos = {
      friends: ["kobe", "james", "curry"],
      [Symbol.iterator]: function() {
        let index = 0
        const infosIterator = {
          next: function() {
            // done: Boolean
            // value: 具体值/undefined
            if (index < infos.friends.length) {
              return { done: false, value: infos.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return infosIterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      console.log(item)
    }


    // 可迭代对象必然有一个[Symbol.iterator]函数
    // 数组是一个可迭代对象
    const students = ["张三", "李四", "王五"]
    console.log(students[Symbol.iterator])
    const studentIterator = students[Symbol.iterator]()
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())

可迭代对象-可迭代对象优化(了解)

1

   // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
   // 1.迭代infos中friends
    // const infos = {
    //   friends: ["kobe", "james", "curry"],
    //   [Symbol.iterator]: function() {
    //     let index = 0
    //     const infosIterator = {
    //       next: () => {
    //         if (index < this.friends.length) {
    //           return { done: false, value: this.friends[index++] }
    //         } else {
    //           return { done: true }
    //         }
    //       }
    //     }
    //     return infosIterator
    //   }
    // }

    // 2.迭代infos中的key/value
    const infos = {
      name: "why",
      age: 18,
      height: 1.88,

      [Symbol.iterator]: function() {
        // const keys = Object.keys(this)
        // const values = Object.values(this)
        const entries = Object.entries(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < entries.length) {
              return { done: false, value: entries[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      const [key, value] = item
      console.log(key, value)
    }

可迭代对象-原生可迭代对象

验证是否是可迭代对象的办法就是是否能调用[Symbol.iterator]()方法、并且可以使用for of来获取值。

 // 1.数组
    // const names = ["abc", "cba", "nba"]
    // for (const name of names) {
    //   console.log(name)
    // }
    // console.log(names[Symbol.iterator]())

    // 2.Set
    // const set = new Set(["abc", "cba", "nba"])
    // for (const item of set) {
    //   console.log(item)
    // }
    // const setIterator = set[Symbol.iterator]()
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())

    // 3.arguments
    function foo() {
      for (const arg of arguments) {
        console.log(arg)
      }
    }

    foo(123, 321, 111, 222)

可迭代对象-可迭代对象场景

1

 // 1.用在特定的语法上
    const names = ["abc", "cba", "nba"]
    const info = {
      name: "why",
      age: 18,
      height: 1.88,
      [Symbol.iterator]: function() {
        const values = Object.values(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < values.length) {
              return { done: false, value: values[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    function foo(arg1, arg2, arg3) {
      console.log(arg1, arg2, arg3)
    }

    foo(...info)

    // 2.一些类的构造方法中, 也是传入的可迭代对象
    const set = new Set(["aaa", "bbb", "ccc"])
    const set2 = new Set("abc")
    console.log(set2)
    const set3 = new Set(info)
    console.log(set3)


    // 3.一些常用的方法
    const p1 = Promise.resolve("aaaa")
    const p2 = Promise.resolve("aaaa")
    const p3 = Promise.resolve("aaaa")
    const pSet = new Set()
    pSet.add(p1)
    pSet.add(p2)
    pSet.add(p3)
    Promise.all(pSet).then(res => {
      console.log("res:", res)
    })

    function bar() {
      // console.log(arguments)
      // 将arguments转成Array类型
      const arr = Array.from(arguments)
      console.log(arr)
    }

    bar(111, 222, 333)

可迭代对象-自定义类的迭代

把类的类属性迭代。

 class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])
    const p2 = new Person("kobe", 30, 1.98, ["curry", "james", "aonier", "weide"])

    for (const item of p2) {
      console.log(item)
    }

可迭代对象-迭代器的中断(了解)

break、return、throw都可以中断迭代器

  class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          },
          return: () => {
            console.log("监听到迭代器中断了")
            return { done: true }
          }
        }
        return iterator
      }
    }

    
    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])

    for (const item of p1) {
      console.log(item)
      if (item === "kobe") {
        break
      }
    }

生成器-生成器函数基本使用

 /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo() {
      console.log("1111")
      console.log("2222")
      yield
      console.log("3333")
      console.log("4444")
      yield
      console.log("5555")
      console.log("6666")
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo()
    // 调用next方法
    generator.next()
    generator.next()
    generator.next()

生成器-生成器函数参数返回值

生成器配合迭代器的返回值可以返回相关的参数。

关于怎么给next传递参数,需要用到类似于这样子的写法,其中的aaaa是next()调用返回的参数。而name2是相当于形参使用。

传递第一次执行的参数时直接写在函数的形参里面。

// yield "aaaa"
const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
   // const names = ["abc", "cba", "nba"]
    // const iterator = names[Symbol.iterator]()
    // console.log(iterator.next())

    /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      // yield "aaaa"
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      // yield "bbbb"
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"
      return undefined
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo("next1")
    // 调用next方法
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: false, value: "bbbb" }
    // console.log(generator.next()) //  { done: false, value: "cccc" }
    // console.log(generator.next()) // {done: true, value: undefined}

    // 3.在中间位置直接return, 结果
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: true, value: "bbbb" }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }

    // 4.给函数每次执行的时候, 传入参数
    console.log(generator.next())
    console.log(generator.next("next2"))
    console.log(generator.next("next3"))
    // console.log(generator.next())

生成器-生成器函数提前结束

通过return可以直接提前结束,但是我们需要的是可以控制的提前结束。这个时候直接使用return()来代替next()

 

 function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"

      console.log("最后一次执行")
      return undefined
    }

    const generator = foo("next1")

    // 1.generator.return提前结束函数
    // console.log(generator.next())
    // console.log(generator.return("next2"))
    // console.log("-------------------")
    // console.log(generator.next("next3"))
    // console.log(generator.next("next4"))

    // 2.generator.throw向函数抛出一个异常
    console.log(generator.next())
    console.log(generator.throw(new Error("next2 throw error")))
    console.log("-------------------")
    console.log(generator.next("next3"))
    console.log(generator.next("next4"))

生成器-生成器代替迭代器

生成器是特殊的迭代器,所以可以借助生成器来迭代课迭代对象。

 // 1.对之前的代码进行重构(用生成器函数)
    const names = ["abc", "cba", "nba"]
    const nums = [100, 22, 66, 88, 55]

    function* createArrayIterator(arr) {
      for (let i = 0; i < arr.length; i++) {
        yield arr[i]
      }
      // yield arr[0]
      // yield arr[1]
      // yield arr[2]
      // return undefined
    }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // const numsIterator = createArrayIterator(nums)
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())

    // 2.生成器函数, 可以生成某个范围的值
    // [3, 9)
    function* createRangeGenerator(start, end) {
      for (let i = start; i < end; i++) {
        yield i
      }
    }

    const rangeGen = createRangeGenerator(3, 9)
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())

生成器-生成器yield语法糖

yield* 可以直接迭代后面跟着的可迭代对象。

在类里面写生成器和平时不一样

 // 1.yield*替换之前的方案
    // const names = ["abc", "cba", "nba"]
    // const nums = [100, 22, 66, 88, 55]

    // function* createArrayIterator(arr) {
    //   yield* arr
    // }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // 2.yield替换类中的实现
    class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      *[Symbol.iterator]() {
        yield* this.friends
      }
    }

    const p = new Person("why", 18, 1.88, ["kobe", "james", "curry"])
    for (const item of p) {
      console.log(item)
    }

    const pIterator = p[Symbol.iterator]()
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())

异步处理-异步请求代码结构(重要)

生成器函数可以解决一些回调地狱。async和await就是生成器的语法糖。

  // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 1.发送一次网络请求
    // requestData("http://why").then(res => {
    //   console.log("res:", res)
    // })

    /*
      需求: 
        1.发送一次网络请求, 等到这次网络请求的结果
        2.发送第二次网络请求, 等待这次网络请求的结果
        3.发送第三次网络请求, 等待这次网络请求的结果
    */
    // 方式一: 层层嵌套(回调地狱 callback hell)
    // function getData() {
    //   // 1.第一次请求
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)

    //     // 2.第二次请求
    //     requestData(res1 + "kobe").then(res2 => {
    //       console.log("第二次结果:", res2)

    //       // 3.第三次请求
    //       requestData(res2 + "james").then(res3 => {
    //         console.log("第三次结果:", res3)
    //       })
    //     })
    //   })
    // }

    // 方式二: 使用Promise进行重构(解决回调地狱)
    // 链式调用
    // function getData() {
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)
    //     return requestData(res1 + "kobe")
    //   }).then(res2 => {
    //     console.log("第二次结果:", res2)
    //     return requestData(res2 + "james")
    //   }).then(res3 => {
    //     console.log("第三次结果:", res3)
    //   })
    // }

    // 方式三: 最终代码
    // function* getData() {
    //   const res1 = yield requestData("why")
    //   console.log("res1:", res1)

    //   const res2 = yield requestData(res1 + "kobe")
    //   console.log("res2:", res2)

    //   const res3 = yield requestData(res2 + "james")
    //   console.log("res3:", res3)
    // }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3)
    //     })
    //   })
    // })

    // 方式四: async/await的解决方案
    async function getData() {
      const res1 = await requestData("why")
      console.log("res1:", res1)

      const res2 = await requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = await requestData(res2 + "james")
      console.log("res3:", res3)
    }

    const generator = getData()

异步处理-生成器代码的优化(了解)

因为层数很多,我们想要自动调用

 // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 生成器的处理方案
    function* getData() {
      const res1 = yield requestData("why")
      console.log("res1:", res1)

      const res2 = yield requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = yield requestData(res2 + "james")
      console.log("res3:", res3)

      const res4 = yield requestData(res3 + "curry")
      console.log("res4:", res4)

      const res5 = yield requestData(res4 + "tatumu")
      console.log("res5:", res5)
    }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3).value.then(res4 => {
    //         generator.next(res4)
    //       })
    //     })
    //   })
    // })

    // 自动化执行生成器函数(了解)
    function execGenFn(genFn) {
      // 1.获取对应函数的generator
      const generator = genFn()
      // 2.定义一个递归函数
      function exec(res) {
        // result -> { done: true/false, value: 值/undefined }
        const result = generator.next(res)
        if (result.done) return
        result.value.then(res => {
          exec(res)
        })
      }
      // 3.执行递归函数
      exec()
    }

    execGenFn(getData)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值