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())

反復可能なオブジェクト - 反復可能なオブジェクトを作成する (理解)

反復可能オブジェクトと反復子は 2 つのものです。反復子は反復可能オブジェクト内のメソッドです。そのようなオブジェクトは反復子を通じて反復でき、反復を通じて値を取得できます。

 // 将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 を使用して値を取得できるかどうかです。

 // 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)

Iterable オブジェクト - カスタム クラスの反復

クラスのクラス プロパティを反復処理します。

 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())

ジェネレーター - ジェネレーター機能が早期に終了しました

リターンによって直接早期に終了することもできますが、必要なのは制御可能な早期終了です。このとき、next() の代わりに return() を直接使用してください。

 

 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* は、次の反復可能オブジェクトを直接反復できます。

クラス内でのジェネレーターの作成は通常とは異なります

 // 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)

おすすめ

転載: blog.csdn.net/weixin_56663198/article/details/131722983