📝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个小时呕心沥血的整理出来的。感谢观看、点赞、转发、收藏 ⛽️

相关推荐
像风一样自由202029 分钟前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem1 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊1 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术1 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing1 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止2 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall2 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴2 小时前
简单入门Python装饰器
前端·python
袁煦丞3 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作
天天扭码3 小时前
从图片到语音:我是如何用两大模型API打造沉浸式英语学习工具的
前端·人工智能·github