📝javaScript中的「迭代对象」

前言

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

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

迭代器

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

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

迭代器是一个对象,它提供了一种遍历给定数据结构的方法。迭代器对象有一个next()方法,每次调用该方法时,它返回一个包含两个属性的对象:valuedonevalue属性包含当前迭代到的值,而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.pushprototype.popprototype.shiftprototype.unshiftprototype.spliceprototype.sliceprototype.concatprototype.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个小时呕心沥血的整理出来的。感谢观看、点赞、转发、收藏 ⛽️

相关推荐
帅帅哥的兜兜34 分钟前
react中hooks使用
前端·javascript·react.js
吞掉星星的鲸鱼2 小时前
使用高德api实现天气查询
前端·javascript·css
lilye662 小时前
程序化广告行业(55/89):DMP与DSP对接及数据统计原理剖析
java·服务器·前端
....4922 小时前
Vue3 + Element Plus + AntV X6 实现拖拽树组件
javascript·vue.js·elementui·antvx6
zhougl9963 小时前
html处理Base文件流
linux·前端·html
花花鱼4 小时前
node-modules-inspector 可视化node_modules
前端·javascript·vue.js
HBR666_4 小时前
marked库(高效将 Markdown 转换为 HTML 的利器)
前端·markdown
careybobo5 小时前
海康摄像头通过Web插件进行预览播放和控制
前端
TDengine (老段)5 小时前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
杉之6 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue