广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Javascript的迭代器和迭代接口详解
  • 595
分享到

Javascript的迭代器和迭代接口详解

2024-04-02 19:04:59 595人浏览 安东尼
摘要

目录1,什么是迭代器2,自定义迭代接口3,原生语言的迭代总结1,什么是迭代器 每一个可迭代对象都对应着一个可迭代接口[Symbol.iterator]; [Symbol.iterat

1,什么是迭代器

每一个可迭代对象都对应着一个可迭代接口[Symbol.iterator];

[Symbol.iterator]接口并不是迭代器,他是一个迭代器工厂函数,调用该迭代接口即可返回一个待执行状态的迭代器;

不同的原生全局对象都对应着不同的迭代器;

const arr = new Array()
const map = new Map()
const set = new Set()
 
console.log(arr[Symbol.iterator]()) //Array Iterator {}
console.log(map[Symbol.iterator]()) //Mapiterator {}
console.log(set[Symbol.iterator]()) //SetIterator {}

将迭代器状态从待执行状态变为真正的执行:调用迭代器对象的 .next()方法;而其的返回值,就是next()方法的返回值对象:

const iterator = new Array(1, 2, 3, 4)[Symbol.iterator]()
 
console.log(iterator.next()) //{value: 1, done: false}
console.log(iterator.next()) //{value: 2, done: false}
console.log(iterator.next()) //{value: 3, done: false}
console.log(iterator.next()) //{value: 4, done: false}
console.log(iterator.next()) //{value: undefined, done: true}

可以看到,当我执行第四次的时候,也就是对应着arr[3],但此时返回的对象中,done属性依旧是false,而执行第五次时,value变成了undefined,done变成了true,为什么会出现这种情况呢

在解答这个问题之前,我们需要在重新认识一下迭代器:

本质上来说,迭代器对象就是实现了next()方法的对象

const myIterator = {
  next() {
    if (length) {
      return { value: 1, done: false }
    } else {
      return { value: undefined, done: true }
    }
  },
}

如上述,就是一个最简单的迭代器。调用next(),会执行迭代,返回done为false的迭代器生成对象,直到符合某种条件,返回done为true的迭代器生成对象。

你可以简单的把Array迭代器原理看作如下所示:

const myIterator = {
  next() {
    if (length) {
      return { value: 1, done: false }
    } else {
      return { value: undefined, done: true }
    }
  },
}

输出的结果也是一样的:

const iterator = new MyArray(1, 2, 3, 4)[Symbol.iterator]() 
console.log(iterator.next()) //{value: 1, done: false}
console.log(iterator.next()) //{value: 2, done: false}
console.log(iterator.next()) //{value: 3, done: false}
console.log(iterator.next()) //{value: 4, done: false}
console.log(iterator.next()) //{value: undefined, done: true}

那么,之前的问题就迎刃而解了。

或许你已经发现了,我自定义了一个类MyArray,并且我手动改写了他的迭代器接口。那么是否只要为某个不可迭代的对象,实现了[Symbol.iterator],就可以把它变成一个可迭代对象呢?

答案是肯定的。只要你想,你可以为任何对象加上可迭代协议,并把它变成可迭代对象。因为迭代对象的定义便是:实现迭代接口的对象。

2,自定义迭代接口

按照以上思路,我们就可以自己手动实现一个可迭代的Object对象了:

const prototype = {
  [Symbol.iterator]() {
    const entries = Object.entries(this)
    const { length } = entries
    let index = 0
    return {
      next() {
        return index < length
          ? {
              value: {
                key: entries[index][0],
                value: entries[index++][1],
              },
              done: false,
            }
          : { value: undefined, done: true }
      },
    }
  },
}
 
const obj = Object.create(prototype)
obj.name = 'zhang san'
obj.age = 28
 
const objIterator = obj[Symbol.iterator]()
console.log(objIterator.next()) //{value: {key:'name',value:'zhang san'}, done: false}
console.log(objIterator.next()) //{value: {key:'age',value:28}, done: false}
console.log(objIterator.next()) //{value: undefined, done: true}

首先,我们声明了一个改写了迭代接口的对象,接着用Obejct.create()创建了以此对象为原型的obj。

该对象实例本身是没有迭代接口的,但是会沿着原型链去寻找prototype对象是否存在迭代接口。只要能在其原型链上找到迭代接口,那么就代表其是一个可迭代对象。如:

const obJSON = Object.create(obj, {
  name: {
    enumerable: true,
    writable: true,
    value: 'zhang xiao san',
  },
  age: {
    enumerable: true,
    writable: false,
    value: 2,
  },
  secret: {
    enumerable: false,
    writable: true,
    value: 'secret',
  },
})
const sonIterator = objson[Symbol.iterator]()
 
console.log(sonIterator.next()) //{value: {key:'name',value:'zhang xiao san'}, done: false}
console.log(sonIterator.next()) //{value: {key:'age',value:2}, done: false}
console.log(sonIterator.next()) //{value: undefined, done: true}

objSon依旧是一个可迭代对象。

那么现在,我们就通过改造迭代接口[Symbol.iterator]的方式,把一个原本不是迭代类型的对象,变成了可迭代对象。

我们可以用该迭代接口来遍历任何enumerable的属性。但如果你想将enumrable为false的secret属性也遍历出来,那么只需要将迭代接口中的entries改造一下即可,一切皆由你想:

// const entries = Object.entries(this)
 
    const ownKeys = Object.getOwnPropertyNames(this)
    const entries = ownKeys.reduce(
      (result, key) => [...result, [key, this[key]]],
      []
    )

3,原生语言的迭代

以for - of 为例

for (const item of obj) {
  console.log(item)
}
//{key:'name',value:'zhang san'}
//{key:'age',value:28}
 
for (const item of objSon) {
  console.log(item)
}
//{key:'name',value:'zhang xiao san'}
//{key:'age',value:2}

可以看到,无论是obj,还是objSon,都可以正常用for of 循环,并且返回值为迭代器生成对象value属性的值。

你可以这么理解for - of 的机制:后台调用提供的可迭代对象的工厂函数[Symbol.iterator],从而创建一个迭代器,然后自动调用迭代器next执行。done为false,则将迭代器生成对象value赋值给item;done为true,则跳出循环:

const objIterator = obj[Symbol.iterator]()
{
  const { value: item,done } = objIterator.next()
  if(done) break
  console.log(item) //{key:'name',value:'zhang san'}
}
{
  const { value: item,done } = objIterator.next()
  if(done) break
  console.log(item) //{key:'age',value:28}
}
{
  const { value: item,done } = objIterator.next()
  if(done) break
  console.log(item) 
}

不仅仅是for - of,原生语言的迭代机制,都与此类似。数组解构,拓展操作符,Array.from,new Set(),new Map(),Promise.all(),Promise.race(),yield * 操作符等,都属于原生迭代语言。

了解了for - of 循环的机制之后,大家可以观察一下下面的例子:

const arr = [1, 2, 3, 4, 5, 6, 7, 8]
for (const item of arr) {
  console.log(item)
  if (item > 3) break
}
for (const item of arr) {
  console.log(item)
}
//输出结果:1,2,3,4 | 1,2,3,4,5,6,7,8
 
const arrIterator = arr[Symbol.iterator]()
for (const item of arrIterator) {
  console.log(item)
  if (item > 3) break
}
for (const item of arrIterator) {
  console.log(item)
}
//输出结果:1,2,3,4 | 5,6,7,8

循环arr的输出结果与循环arr迭代器arrIterator的结果明显的不同。为什么会出现这种现象呢?

在迭代器对象中,还有一个很重要的知识点:迭代器对象是一个一次性的,不可逆的对象。

因此,在迭代中某个地方终止,那么只能接着上一次终止的位置继续执行,而不会从头开始。

那么为什么对于arr本身使用for - of,却没有接着执行而是从头开始呢?可以回到介绍for - of 循环机制的那部分,其中有一句话:后台调用提供的可迭代对象的工厂函数[Symbol.iterator],从而创建一个迭代器

也就是说,每调用一次for - of循环,都会创建一个新的迭代器对象,而该迭代器对象,在循环结束时就会被当作垃圾对象被回收。

虽然arr连续调用了两次for - of循环,但是在循环体的内部,并不是同一个迭代器对象。因此,即使上一个迭代器在item>3这个条件处中止了,但是下一次循环的迭代器对象,是一个全新的,还没有执行过的迭代器对象。

那么对于调用arr[Symbol.iterator]接口生成的的迭代器对象arrIterator,为什么会出现继续上次执行的情况呢,换句话说,为什么arrIterator的两次for循环,没有产生两次迭代器对象?

其实,迭代器对象本身,也实现了迭代器接口,也就是说。arr有一个迭代器接口[Symbol.iterator],而迭代器对象arrIterator也有一个迭代器接口[Symbol.iterator],并且,调用该迭代器对象,返回其本身:

console.log(arrIterator[Symbol.iterator]() === arrIterator) // true

所以虽然每次执行for-of循环都会同样的调用迭代器接口,但是该迭代器接口返回的对象就是arr的迭代器对象本身,而迭代器对象是一个一次性,不可逆的对象。因此,为什么会出现上述现象,也就显而易见了。

细心的朋友可能会想到一个问题:我们在之前手动实现的可迭代对象,其迭代器对象是否支持了迭代接口?是的,他不能

for (const item of objIterator) {
  console.log(item)
}
//Uncaught TypeError: objIterator is not iterable

但其实我们要优化也很简单,只要将该迭代器对象也实现一个迭代接口,并且该迭代接口工厂函数返回其本身,即可。

const prototype = {
  [Symbol.iterator]() {
    // const entries = Object.entries(this)
 
    const ownKeys = Object.getOwnPropertyNames(this)
    const entries = ownKeys.reduce(
      (result, key) => [...result, [key, this[key]]],
      []
    )
    const { length } = entries
    let index = 0
    return {
      next() {
        return index < length
          ? {
              value: {
                key: entries[index][0],
                value: entries[index++][1],
              },
              done: false,
            }
          : { value: undefined, done: true }
      },
      [Symbol.iterator]() {
        return this
      },
    }
  },
}
 
const objIterator = obj[Symbol.iterator]()
 
for (const item of objIterator) {
  console.log(item)
  if (item.key === 'name') break
}
for (const item of objIterator) {
  console.log(item)
}
// {key: 'name', value: 'zhang san'}
// {key: 'age', value: 28}

现在,你可以用文中所介绍的方法,将任何对象变成一个可迭代对象。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Javascript的迭代器和迭代接口详解

本文链接: https://www.lsjlt.com/news/144476.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Javascript的迭代器和迭代接口详解
    目录1,什么是迭代器2,自定义迭代接口3,原生语言的迭代总结1,什么是迭代器 每一个可迭代对象都对应着一个可迭代接口[Symbol.iterator]; [Symbol.iterat...
    99+
    2022-11-13
  • 详解Python迭代和迭代器
    我们将要来学习python的重要概念迭代和迭代器,通过简单实用的例子如列表迭代器和xrange。 可迭代 一个对象,物理或者虚拟存储的序列。list,tuple,strins,dicttionary,set...
    99+
    2022-06-04
    迭代 详解 Python
  • Python迭代和迭代器详解
    迭代器 迭代器(iterator)有时又称游标(cursor)是程式设计的软件设计模式,可在容器物件(container,例如链表或阵列)上遍访的界面,设计人员无需关心容器物件的内存分配的实现细节。 摘自维...
    99+
    2022-06-04
    迭代 详解 Python
  • JavaScript中Iterator迭代器接口和循环
    目录JavaScript的迭代器(Iterator)介绍for...of循环与for...in循环JavaScript的迭代器(Iterator)介绍 迭代器是数据结构遍历的一种机制...
    99+
    2022-11-13
  • Java迭代器与Collection接口超详细讲解
    目录关于迭代器你都知道什么什么是迭代器迭代器的4个API如何使用迭代器?Collection集合接口知多少为什么不使用数组而是集合Collection接口的API都有什么Abstra...
    99+
    2022-11-13
  • 详解Python之可迭代对象,迭代器和生成器
    目录一、概念描述二、序列的可迭代性三、经典的迭代器模式四、生成器也是迭代器五、实现惰性迭代器六、使用生成器表达式简化惰性迭代器总结 一、概念描述 可迭代对象就是可以迭代的对象,我们可...
    99+
    2022-11-12
  • JavaScript中的迭代器和可迭代对象与生成器
    目录1. 什么是迭代器?1.1 迭代器的基本实现1.2 迭代器的封装实现2. 什么是可迭代对象2.1 原生可迭代对象(JS内置)2.1.1 部分for of 演示2.1.2 查看内置...
    99+
    2022-11-13
  • C++迭代器iterator详解
    目录1.迭代器分类1) 正向迭代器2) 常量正向迭代器3) 反向迭代器4) 常量反向迭代器2.迭代器用法示例3.迭代器:++it 与 it++ 哪个好?(1)前置返回一个引用,后置返...
    99+
    2022-11-12
  • python yield迭代器详解
    目录一、yield迭代器二、使用步骤1.引入库2.读入数据总结一、yield迭代器 在python深度学习模型读取数据时,经常遇到yield,互联网搜索后,将比较容易理解的说明记录一...
    99+
    2022-11-13
    python yield python yield迭代器
  • JavaScript迭代器与生成器使用详解
    目录迭代器 (Iterator)Iterator工作原理自定义遍历数据生成器 (Generator)生成器参数传递使用生成器实现回调地狱功能生成器函数实例生成器—thro...
    99+
    2022-11-13
    JavaScript迭代器与生成器 JavaScript生成器 JavaScript迭代器
  • Python 的迭代器与zip详解
    目录关于迭代器关于zip总结:首先抛出一个困扰本人许久的问题: nums = [1,2,3,4,5,6] numsIter = iter(nums) for _ in zip(*...
    99+
    2022-11-12
  • 详解ES6 中的迭代器和生成器
    目录1.迭代器2.生成器1.迭代器 Iterator是 ES6 引入的一种新的遍历机制。两个核心 迭代器是一个统一的接口,它的作用是使各种数据结构可以被便捷的访问,它是通过一个键为S...
    99+
    2022-11-13
    ES6 中的迭代器和生成器 ES6 迭代器 ES6生成器
  • python迭代器,生成器详解
    目录迭代器 生成器 总结迭代器 聊迭代器前我们要先清楚迭代的概念:通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结...
    99+
    2022-11-12
  • Java数据结构算法Collection接口迭代器示例详解
    目录Java合集框架Collection接口迭代器Java合集框架 数据结构是以某种形式将数据组织在一起的合集(collection)。数据结构不仅存储数据,还支持访问和处理数据的操...
    99+
    2022-11-13
  • Python学习之迭代器详解
    目录什么是迭代器如何生成迭代器迭代器函数 - iter() 函数 与 next() 函数可迭代的对象生成迭代器迭代器的用法 - 演示案例什么是迭代器 迭代是 python 中访问集合...
    99+
    2022-11-13
  • 详解nodejs中的异步迭代器
    目录前言什么是异步迭代器作为异步迭代器流调用有分页功能的 API前言 从 Node.jsv10.0.0 开始,异步迭代器就出现中了,最近它们在社区中的吸引力越来越大。在本文中,我们将...
    99+
    2022-11-12
  • python迭代器与生成器详解
    例子 老规矩,先上一个代码: def add(s, x): return s + x def gen(): for i in range(4): yield i base = gen() ...
    99+
    2022-06-04
    生成器 详解 迭代
  • JavaScript中可迭代对象与迭代器的作用是什么
    今天就跟大家聊聊有关JavaScript中可迭代对象与迭代器的作用是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Lazy evaluation...
    99+
    2022-10-19
  • JavaScript Lazy evaluation中可迭代对象与迭代器是怎样的
    今天就跟大家聊聊有关JavaScript Lazy evaluation中可迭代对象与迭代器是怎样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。L...
    99+
    2022-10-19
  • 怎样理解Python迭代对象和迭代器以及生成器
    这篇文章将为大家详细讲解有关怎样理解Python迭代对象和迭代器以及生成器,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。在了解Python的数据结构时,容器(container)、可迭代对象...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作