可迭代对象

◼ 但是上面的代码整体来说看起来是有点奇怪的:
  我们获取一个数组的时候,需要自己创建一个index变量,再创建一个所谓的迭代器对象;
  事实上我们可以对上面的代码进行进一步的封装,让其变成一个可迭代对象;
◼ 什么又是可迭代对象呢?
  它和迭代器是不同的概念;
  当一个对象实现了iterable protocol协议时,它就是一个可迭代对象;
  这个对象的要求是必须实现@@iterator 方法,在代码中我们使用Symbol.iterator 访问该属性;
◼ 当然我们要问一个问题,我们转成这样的一个东西有什么好处呢?
  当一个对象变成一个可迭代对象的时候,就可以进行某些迭代操作;
  比如for...of 操作时,其实就会调用它的@@iterator 方法;

手写一个可迭代对象

    // 将infos变成可迭代对象
    //1.必须有一个函数叫:[Symbol.iterator]
    //2.这个函数需要返回一个迭代器(这个迭代器用于返回当前这个对象)
    //3.
    const infos = {
      friends:["kebo","james","curry"],
      [Symbol.iterator](){
        let index = 0
        const infosIterator = {
          next(){
            if(index < infos.friends.length){
              return {done:false,value:infos.friends[index++]}
            }
            else{
              return{done:true,value:undefined}
            }
          }
        }
        return infosIterator
      }
    }
    // 可迭代对象必然具备下面的特点
    // 一定可以这样拿到一个函数执行后一定拿到一个迭代器
  const iterator =  infos[Symbol.iterator]()
  // 一定可以通过迭代器.next()
  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)
  }

可迭代对象迭代出来的值为key:value

// 将infos变成可迭代对象
//1.必须有一个函数叫:[Symbol.iterator]
//2.这个函数需要返回一个迭代器(这个迭代器用于返回当前这个对象)
//3.
const infos = {
  friends:["kebo","james","curry"],

  // 迭代infos中的friends数组
//   [Symbol.iterator](){
//     let index = 0
//     const infosIterator = {
//       next: () => {
//         if(index < this.friends.length){
//         // next()为普通函数时this指向的是iterator并不是infos 所有next函数要用箭头函数this为上层作用域的this
//           return {done:false,value:this.friends[index++]}
//         }
//         else{
//           return{done:true,value:undefined}
//         }
//       }
//     }
//     return infosIterator
//   }
// }
// 迭代infos中的key和value
  name:"hdc",
  age:21,
  height:1.88,
  [Symbol.iterator](){
    const keys = Object.keys(this)//key的值
    const values = Object.values(this)//value值
    const entries = Object.entries(this)//key:value值
    let index = 0
    const iterator = {
      next:()=>{
          if (index < entries.length){
            return {done:false , value:entries[index++],}
          }
          else{
            return{done:true,value:undefined}
        }
      }
    }
    return iterator
  }

}
// 可迭代对象必然具备下面的特点
// 一定可以这样拿到一个函数执行后一定拿到一个迭代器
//  const iterator =  infos[Symbol.iterator]()
//  // 一定可以通过迭代器.next()
//  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值为:${key},value值为:${value}`)
}

原生迭代器对象

  ◼ 事实上我们平时创建的很多原生对象已经实现了可迭代协议,会生成一个可迭代对象的:
  String、Array、Map、Set、arguments对象、NodeList集合;
   // 1.Array
    const names = ["aaa","bbb","ccc"]
    for(const name of names){
      console.log(name)
    }
    console.log(names[Symbol.iterator]())

    //2.Set
    const set = new Set(["aaa","bbb","ccc"])
    for (const item of set) {
        console.log(item)
    }
    console.log(set[Symbol.iterator]())
    //3.arguments
    function foo(){
      for (const arg of arguments) {
        console.log(arg)
      }
      console.log(arguments[Symbol.iterator]())
    }
    foo(111,222,33,44,112,55)

可迭代对象的应用

   ◼ 那么这些东西可以被用在哪里呢?
      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 arrs = ["aaa","bbb","ccc","ddd"]
      //JavaScript中语法
      //for of 语法
      for (const arr of arrs) {
        console.log(arr)
      }
      // 展开运算符
      const newArr = [...arrs]
      console.log(newArr)
      // 结构
      const[arr1,arr2,arr3,arr4]=arrs
      console.log(arr1,arr2,arr3,arr4)

      // 一些类的构造方法中,也是传入一些可迭代对象
      const set = new Set(["aaaa","bbbb","cccc"])

自定义类的迭代

◼ 在前面我们看到Array、Set、String、Map等类创建出来的对象都是可迭代对象:
    在面向对象开发中,我们可以通过class定义一个自己的类,这个类可以创建很多的对象:
    如果我们也希望自己的类创建出来的对象默认是可迭代的,那么在设计类的时候我们就可以添加上@@iterator 方法;
◼ 案例:创建一个classroom的类
    教室中有自己的位置、名称、当前教室的学生;
    这个教室可以进来新学生(push);
    创建的教室对象是可迭代对象;
   class classRoom {
      constructor(postion,name,students){
        this.postion = postion
        this.name = name
        this.students = students
      }
      pushStudent(student){
        this.students.push(student)
      }
      [Symbol.iterator](){
        let index = 0
        const iterator = {
            next:()=>{
              if(index < this.students.length){
                return {done:false,value:this.students[index++]}
              }
              else{
                return {done:true,value:undefined}
              }
            }
        }
        return iterator
      }
    }
  const classRoom1 = new classRoom("xxx楼101","WEB教室",["aaa","bbb","ccc"])
  classRoom1.pushStudent("ddd")
  console.log(classRoom1)
  let index = 1
  for (const student of classRoom1) {
      console.log(`教室的学生${index++}:${student}`)
  }

迭代器的中断

  ◼ 迭代器在某些情况下会在没有完全迭代的情况下中断:
      比如遍历的过程中通过break、return、throw中断了循环操作;
      比如在解构的时候,没有解构所有的值;
  ◼ 那么这个时候我们想要监听中断的话,可以添加return方法:
    class classRoom {
          constructor(postion,name,students){
            this.postion = postion
            this.name = name
            this.students = students
          }
          pushStudent(student){
            this.students.push(student)
          }
          [Symbol.iterator](){
            let index = 0
            const iterator = {
                next:()=>{
                  if(index < this.students.length){
                    return {done:false,value:this.students[index++]}
                  }
                  else{
                    return {done:true,value:undefined}
                  }
                },
                // 迭代器中断函数
                return:function(){
                  console.log("箭头到迭代器中断")
                  return {done:true}
                }
            }
            return iterator
          }
        }
      const classRoom1 = new classRoom("xxx楼101","WEB教室",["aaa","bbb","ccc"])
      classRoom1.pushStudent("ddd")
      console.log(classRoom1)
      let index = 1
      for (const student of classRoom1) {
        console.log(student)
        if (student === "ccc"){
          break
        }
      }
posted @ 2024-10-21 10:49  韩德才  阅读(8)  评论(0编辑  收藏  举报