JavaScript高级(十六)---Iterator迭代器/Generator生成器

本文详细解释了迭代器的概念,包括其next方法的工作原理,以及如何通过可迭代对象和for..of等语法使用。同时介绍了生成器的功能,如控制函数执行流程和处理异步操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 什么是迭代器?

迭代器是一种特殊的对象,这个对象需要符合迭代协议(iterator protocol),这个对象具有以下特点。

  • 该对象有一个特定的next方法

    const obj = {
        next() {
        }
    }  
 

    const obj = {
        next() {
            return { done:(boolean) , value:...}
        }
    }
 

例如:创建一个迭代器对象来访问数组

  • next方法形参是一个无参数或者有一个参数的函数,返回一个应当拥有以下两个属性的对象

  • done(boolean)
    • 如果迭代器可以产生序列中的下一个值,则为 false。
    • 如果迭代器已将序列迭代完毕,则为 true。这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值。
  • value
    • 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。
    const arr = ["a", "b", "c", "d", "e", "f"]

    let index = 0;
    const iteratorArr = {
      next() {
        if (index < arr.length) {
          return { done: false, value: arr[index++] }
        } else {
          return { done: true, value: undefined }
        }
      }
    }

    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
    console.log(iteratorArr.next())
可迭代对象

可迭代对象和迭代器是一个不同的概念,当一个对象实现了iterator protocol协议时,它就是一个可迭代对象,这个对象必须实现@@iterator方法,在代码中我们可以用[Symbol.iterator]来访问该属性。

当一个对象变成可迭代对象的时候,进行某些迭代操作,比如for..of,其实就是调用的它的@@iterator方法。

  • 可迭代对象代码
      const arrIterator = {
      arr: ["a", "b", "c", "d", "e", "f"],
      //实现iterator protocol协议 , 使用[Symbol.iterator]访问@@iterator
      [Symbol.iterator]() {
        let index = 0;
        //迭代器 一个特殊的对象
        return {
          // 特定的方法next()
          next: () => {
            // 返回一个对象 包含两个属性 done value
            if (index < this.arr.length) {
              return { done: false, value: this.arr[index++] };
            } else {
              return { done: true, value: undefined }
            }
          }
        }
      }
    }

    const iterator = arrIterator[Symbol.iterator]();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    
原生迭代器对象

事实上我们平时创建的很多原生对象已经实现了可迭代协议,会生成一个迭代器对象的,例如String,Array,Set,arguments,NodeList;

 // String 内部实现了可迭代协议
    var str = "Hello World";
    console.log(str[Symbol.iterator]())
    // for .. of 实际上都是在调用迭代器
    for (const item of str) {
      console.log(item)
    }
    // 展开运算符 实际上都是在调用迭代器
    console.log(...str)


    // Map,Set
    var map = new Map();
    map.set('a', {})
    map.set('b', {})

    console.log(map[Symbol.iterator])

    // 展开运算符 实际上都是在调用迭代器
    console.log(...map)


    // arguments
    function foo(x, y, z) {
      console.log(arguments[Symbol.iterator])
      // 展开运算符 实际上都是在调用迭代器
      console.log(...arguments)
    }
    foo(1, 2, 3)
可迭代对象的应用
  • JavaScript中语法:for ...of、展开语法(spread syntax)、yield*(后面讲)、解构赋值(Destructuring_assignment);
  • 创建一些对象时:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
  • 一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);
     // 展开运算符 
    const names = ["haha", "gaga", "heihei"]
    console.log(...names) //names内部有迭代协议

    // 对象内部没有可迭代协议 也不能进行for of
    const obj = {
      a: "1",
      b: "2",
      c: "3"
    }
    // ES9(ES2018)中新增的一个特性,用的不是迭代器
    console.log({ ...obj })


    // 解构语法
    const [haha, ...rest] = names
    console.log(haha, rest)

    // ES9(ES2018)中新增的一个特性,用的不是迭代器
    const { a, ...args } = obj
    console.log(a, args)
迭代器的中断

比如遍历的过程中通过break、continue、return、throw中断了循环操作;

    class classRoom {
      constructor(address, name, students) {
        this.address = address;
        this.name = name;
        this.students = students;
      }

      entry(student) {
        this.students.push(student);
      }

      [Symbol.iterator]() {
        let index = 0;
        return {
          next: () => {
            if (index < this.students.length) {
              return { done: false, value: this.students[index++] };
            } else {
              return { done: true, value: undefined };
            }
          },
          // 想要监听中断的话,可以添加return方法
          return() {
            return { done: true, value: undefined };
          }
        }
      }

    }

    const classroom = new classRoom("3幢5楼205", "计算机教室", ["james", "kobe", "curry", "why"])
    classroom.entry("lilei")

    for (const stu of classroom) {
      if (stu === 'kobe') break;
      console.log(stu)
    }

什么是生成器?

生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。

平时我们会编写很多的函数,这些函数终止的条件通常是返回值或者发生了异常。

  • 生成器也是一个函数
    • 首先,生成器函数需要在function的后面加一个符号:*
    • 其次,生成器函数可以通过yield关键字来控制函数的执行流程:
    • 最后,生成器函数的返回值是一个Generator(生成器):
    • 生成器实际上是一个特殊的迭代器

生成器函数执行
      function* foo() {
      console.log("----start----")

      const value1 = 30
      console.log(value1)
      yield

      const value2 = 30
      console.log(value2)
      yield

      const value3 = 30
      console.log(value3)
      yield

      const value4 = 30
      console.log(value4)
      yield

      console.log("----end----")

      return "ok"

    }
    
    // 这里不会调用函数,只是返回了一个遍历器对象,可以通过.next()调用
    const f = foo();
    console.log(f)
    
    f.next()
    f.next()
    f.next()
    f.next()
    f.next()
    f.next()
生成器传递参数
function* foo(num) {
      console.log("----start----")

      console.log(num)
      // x 不是yield的返回值,它是调用next() 回复当前 yield()执行传入的实参
      let x = yield '1'      //第一次执行 f.next() 会暂停在这里 . 第二次执行yield 如果传入了形参,就会赋值给x
      console.log('x' + x); 

      let y = yield '2'
      console.log('y' + y)

      let z = yield '3'
      console.log('z' + z)


      console.log("----end----")
      return "ok"

    }

    // 这里不会调用函数,只是返回了一个遍历器对象,可以通过.next()调用
    const f = foo(5);
   
    f.next()   // 如果第一次就想传值  只能在foo() 这里面添加形参
    f.next(1)
    f.next(2)
    f.next(3)

生成器异步解决方案

   // request.js
    function requestData(url) {
      // 异步请求的代码会被放入到executor中
      return new Promise((resolve, reject) => {
        // 模拟网络请求
        setTimeout(() => {
          // 拿到请求的结果
          resolve(url)
        }, 2000);
      })
    }

    function* getData() {
      console.log('+++++')
      const res1 = yield requestData("第一次发送网络请求")
      const res2 = yield requestData("第二次发送网络请求" + res1)
      const res3 = yield requestData("第二次发送网络请求" + res2)
      console.log(res3 + '------')
      return 1
    }


    const generator = getData();
    // res1 res2 res3 都是形参
    generator.next().value.then(res => {
      console.log(res)
      generator.next('2').value.then(res => {
        console.log(res)
        generator.next('3').value.then(res => {
          console.log(res)
          generator.next('4').value.then(res => {
            console.log(res)
          })
        })
      })
    })

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值