📝javaScript中的「迭代对象」

前言

在JavaScript中,迭代对象的概念是在ES6(ECMAScript 2015)规范中引入的。ES6引入了迭代器(Iterator)和可迭代对象(Iterable)的概念,以及相关的语法和API。

可迭代对象是一个对象,它有一个[Symbol.iterator]方法,该方法返回一个迭代器对象。这意味着你可以使用for...of循环来遍历可迭代对象的值。

迭代器

迭代器是借鉴C++等语言的概念,迭代器的原理就像指针一样,它指向数据集合中的某个元素,你可以获取它指向的元素,也可以移动它以获取其它元素。迭代器类似于数组中下标的拓展,各种数据结构,如链表(List)、集合(Set)、映射(Map)都有与之对应的迭代器。

JS中的迭代器是专门为了遍历这一操作设计的。每次获取到的迭代器总是初始指向第一个元素,并且迭代器只有next()一种行为,直到获取到数据集的最后一个元素。我们无法灵活移动迭代器的位置,所以迭代器的任务,是按某种次序遍历数据集中的元素。

迭代器是一个对象,它提供了一种遍历给定数据结构的方法。迭代器对象有一个next()方法,每次调用该方法时,它返回一个包含两个属性的对象:value和done。value属性包含当前迭代到的值,而done属性是一个布尔值,表示是否还有更多的值可以迭代。

调用数组的迭代器

先认识下数组的迭代器(Symbol.unscopables)它存在于数组的原型上,如下图:

直接调用Symbol.iterator属性就可以调用数组的迭代器。

js 复制代码
  let arr = ["a", "b"]
  let arrIterator = arr[Symbol.iterator]()
  console.log(arrIterator.next()) // {value: 'a', done: false}
  console.log(arrIterator.next()) // {value: 'b', done: false}
  console.log(arrIterator.next()) // {value: undefined, done: true}

上面我们也提到了可迭代对象的特点是有一个[Symbol.iterator]方法,拥有该方法的对象是可以被for...of...遍历的。那么哪些数据结构可以被for...of..遍历呢?

常见的有以下几种:Array、String、Set 和 Map,特殊类数组对象:arguments、NodeList 等,下面以Set和Map数据结构为例:

1. Set()数据结构

js 复制代码
  const set = new Set([1, 2, 3, 4, 4])
  for (const value of set) {
    console.log(value) // 1 2 3 4
  }

2. Map()数据结构

js 复制代码
  const map = new Map([
    ["name", "张三"],
    [
      {
        a: "Hello World",
      },
      "你好",
    ],
  ])
  for (let [name, value] of map) {
    console.log("name:", name) // name: name  // name: {a: 'Hello World'}
    console.log("value:", value) // value: 张三  // value: 你好
  }

为类数组添加迭代器

在JavaScript中,"类数组"(array-like)对象是指那些具有数字索引的属性和长度属性,但没有prototype.push、prototype.pop、prototype.shift、prototype.unshift、prototype.splice、prototype.slice、prototype.concat、prototype.join等方法可调用的对象。类数组对象最常见的例子是字符串和NodeList对象。

类数组对象并不是真正的数组,但它们具有与数组相似的特性,例如索引属性和长度属性。由于类数组对象没有数组的方法,因此不能直接使用数组的方法来处理它们。

使用for...of...遍历类数组

js 复制代码
  const arrayLike = {
    0: "a",
    1: "b",
    2: "c",
    length: 3,
  }
  for (let value of arrayLike) {
    console.log(value) // Uncaught TypeError: arrayLike is not iterable
  }

🙅显然是不行滴!!!所以需要添加迭代器。

js 复制代码
  const arrayLike = {
    0: "a",
    1: "b",
    2: "c",
    length: 3,
  }

  arrayLike.__proto__[Symbol.iterator] = function () {
    let index = 0
    return {
      next: () => {
        return this.length > index
          ? {value: this[index++], done: false}
          : {value: undefined, done: true}
      },
    }
  }
  for (let value of arrayLike) {
    console.log(value) // a b c
  }

以上是为类数组添加迭代器的方法,如果你没有看懂,建议仔细阅读迭代器的概念。

既然类数组可以添加迭代器,那么普通对象能不能添加迭代器呢?

普通对象添加迭代器

分析:普通对象并不像类数组那样对象的key是一堆有序的数字,并且也没有长度,所以在为普通对象添加迭代器的时候先解决这两个问题,不妨我们试试先遍历对象。

js 复制代码
  let man = {
    name: "小明",
    age: 20,
  }

  man.__proto__[Symbol.iterator] = function () {
    let keys = []
    let index = 0
    for (let key in this) {
      // 筛选自身属性
      if (this.hasOwnProperty(key)) {
        keys.push(key)
      }
    }
    return {
      next: () => {
        return keys.length > index
          ? {value: this[keys[index++]], done: false}
          : {value: undefined, done: true}
      },
    }
  }

  for (let v of man) {
    console.log(v)  // 小明 20
  }

如果为类数组添加迭代器已经看懂,相信为普通对象添加迭代器你也能看懂💪

后记

创作是一个复杂的过程,需要将思考、灵感和技巧完美结合,每一次的成功都来之不易。以上是我花费了N个小时呕心沥血的整理出来的。感谢观看、点赞、转发、收藏 ⛽️

相关推荐
梦帮科技1 小时前
Web 漏洞攻防深度:WAF 规则逃逸技术(畸形分块传输、双重编码)与对抗加固
linux·前端·网络安全·ssl·web
兰亭妙微UI设计公司1 小时前
兰亭妙微软件界面设计公司的解锁按钮设计10大密码
开发语言·前端·javascript
救救孩子把1 小时前
AI面试八股文-03_3-RAG 系统面试题
人工智能·redis·面试·agent·rag
迪幻1 小时前
封装自己的 npm 依赖并存储到个人 GitHub
前端·npm·github
u0111026752 小时前
WebP 转成 PNG 后为什么更大?图片格式转换不等于压缩
前端·javascript·vue.js
万少2 小时前
Qoder sonus模型 20分钟,复刻 马斯克 飞天汽车
前端·后端·算法
java1234_小锋2 小时前
【技术专题】HTML5 网页技术 - HTML5 列表标签
前端·html·html5
强二小哥帅2 小时前
Kotlin 协程复习笔记
前端
不可能片场2 小时前
工程实践 原子替换改了 ctime 怎么修
前端·electron
暧暧内含光2 小时前
HTTP 文件传输体系全解:从协议标头、OSS 架构到流媒体分片
前端