广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >详解JS前端使用迭代器和生成器原理及示例
  • 274
分享到

详解JS前端使用迭代器和生成器原理及示例

JS前端迭代器生成器JS迭代器生成器 2023-02-21 12:02:42 274人浏览 独家记忆
摘要

目录正文for of 是干什么用的可迭代对象是什么?生成器和迭代器的关系。让非迭代对象也可以使用for of 进行遍历for循环和for in的关系总结正文 生成器和迭代器这两个东

正文

生成器和迭代器这两个东西平时作为一个切图仔,一直都没有使用到。感觉是只有在面试之前才会的东西。面试过不了几天,再次看这两个词一阵恍惚。

记忆力退化成这样了么?最大的原因一定是用得少了。然后呢?就是没有真正的理解它们。我对于它们的认知常常有下面这些:

1. 我常常把迭代器和生成器理解成完全不同的东西。

2. 我常常把for、forEach、map、reducefor of混为一谈

3. 我常常把数组、类数组认为是可迭代对象

想来要真正的记住它,增加自己的武器库,必须要弄明白这些东西才行。

我们首先是要搞明白什么for of是干什么用的。

业务代码确实使用不上,但是如果不理解的话,等真到了可以使用的场景的时候,又是否真的能够运用起来,甚至记起来呢?

for of 是干什么用的

所有人都知道一些概念for、forEach、map、reduce这些是可以遍历数组的,for of是用于遍历迭代对象的。如下:

const arr = [1, 2, 3]
arr.forEach((item, index) => {
   console.log(item) // 1, 2, 3 
   console.log(index) // 0, 1, 2
})

而巧合的是for of也可以遍历数组

for (let key of arr) {
    console.log(key) // 1 2 3
}

将arr改变为const obj = { a: 1, b: 2, c: 3 }的时候,两者都没有遍历出结果。

前者是没有反应,后者会直接报错:TypeError: obj is not iterable翻译一下,类型错误:obj 不是一个可迭代对象。

那么什么是可迭代对象呢?

可迭代对象是什么?

我们先来看看下面这个例子:

const itemLi1 = document.getElementByTagName('li')
const itemLi2 = document.querySelectorAll('li')
for(let key of itemLi1) {
    console.log(item)
}
for(let key of itemLi2) {
    console.log(item)
}

也就是说htmlCollectionnodeList是可以迭代对象。其他的可迭代对象有Array、map、set、string等等。如果说类数组的话,是不是迭代对象呢?

const arrLike = {
  0: 1,
  1: 2,
  2: 3,
  lenght: 3
}
for (let i = 0; i < arrLike.length; i++) {
    console.log(arrLike[i]) // 1, 2, 3
}
for (let of arrLike) {
    console.log(key) // uncachh TypeError: obj is not iterable
}

for循环打印出了对应的结果,而for of 报错了。类数组不是可迭代的的对象。这又是为什么呢?我们将类数组和HTMLCollection类型打印出来比较一下。

而类数组如下:

它们有一个明显的不同,可迭代对象的原型链上面是包括Symbol.iterator的。而这个就是让数组变成可迭代的根本原因。

也就是说,当目的对象的原型链上面包括Symbol.iterator的时候,它才是可迭代对象。

对象是无序的,无序的东西自然不可以迭代

这里使用到了Symbol类型,它在MDN上面的解释就是用于生成全局唯一的变量。而可迭代对象就是它的使用场景。受它的启发,我们在业务当中,如果需要前端来生成一个唯一ID的时候,再次之前,通常都是创建一个UUID的函数来生成一个唯一ID。Symbol不用这么麻烦,直接使用就可以了。

由此可知,Array.prototype[Symbol.iterater]这个函数封装了一些东西,使得for of可以将对象的元素给打印出来。

换一句话来说,就是Array.prototype[Symbol.iterater] = function() {}的执行生成一个迭代器对象。

也就是说,当Object.prototype也有[Symbol.iterater]的方法的时候,for of也能够遍历它呢?我们来试试看吧。

Object.ptotoype[Symbol.iterator] = function value() {}

这不就是生成器的作用么?

生成器和迭代器的关系。

es6给我提高了一个生成器的函数。既然叫做生成器,它生成的东西就是迭代器。

表现形式如下:

function * generation(iterableObject) {
    for(let i = 0; i < iterableObject; i++) {
        yield iterableObject[i]
    }
}

*符号和yield关键字组成。

const iterator = generation([1, 2, 3]), 其执行流程如下:

iterator.next() ==> { value: 1, done: false }

iterator.next() ==> { value: 2, done: false }

iterator.next() ==> { value: 3, done: false }

iterator.next() ==> { value: undefined, done: true }

到了第四次,value为undefined的时候,done为true(也就是说,当done为true的时候,value一定为undefined)。所以说,yield的作用有两个:

  • 生成一个值,将该值封装成一个对象,而这个对象是{ value: .., done: flase/true }这样的形式。
  • 停下来

可以明显的看出来,生成器有一个作用,通过next这个接口,可以看到迭代的过程。

既然说生成器生成了一个迭代器,那么是不是说生成器执行后的结果就是一个迭代器呢?既然是迭代器,自然就可以被for of给遍历。

for (const key of generation([1, 2, 3]) {
    console.log(key) // 1, 2, 3
}

果然可以。

经典面试题: 自己实现一个next这样的接口呢?

上面已经有了实现的思路。通过一个标识符和一个判断就能够使用ES5来使用,如下代码片段。

function generation(iterableObj) {
    let nextIndex = 0
    function next() {}
    return {
        next: () => {
            return nextIndex < iterableObj.length
                             ? { value: iterableObj[nextIndex++], done: false }
                             : { value: undefined, done: true } 
        }
    }
}

当nextIndex下于数组长度的时候,没有迭代完毕。

注意:nextIndex++是先跑nextIndex,再自增。

何为接口,后台给你一个url地址,这个是网络接口。next是设计师给你封装的一个方法,你通过这个方法来达到上吧yield的两个作用,所以next()也是一个接口,前端接口。简单来说,一个封装好的方法就是一个接口。

让非迭代对象也可以使用for of 进行遍历

正如第一节所说,Symbol.iterator的方法是迭代器的关键。那么我们也可以给Object挂载上该方法。既然该方法可以让对象变成迭代器,就可以直接使用上面ES5实现next方法的代码片段。

const obj = {
  a: 1,
  b: 2,
  c: 3
}
Object.prototype[Symbol.iterator] = function value() {
  const keys = Object.keys(Object(this))
  let nextIndex = 0
  function next() {
    return nextIndex < keys.length
        ? { value: [keys[nextIndex], obj[keys[nextIndex ++]]], done: false }
        : { value: undefined, done: true }
  }
  return {
    next
  }
}
for (const [key, value] in obj) {
  console.log(key)
}

for循环和for in的关系

for循环和for in 看着很像,其实只是共用了for这个关键字,它们都是js引擎底层实现的东西。和forEach、map这些是基于for循环的api不同,它们是在实现在for循环之上的。

总结

  • 生成器generator执行的结果就是一个迭代器
  • 生成器可以是也是由ES5实现的,不是基于底层API
  • 是否是迭代器的关键是Symbol.iterator方法

以上就是详解JS前端使用迭代器和生成器原理及示例的详细内容,更多关于JS前端迭代器生成器的资料请关注编程网其它相关文章!

--结束END--

本文标题: 详解JS前端使用迭代器和生成器原理及示例

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

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

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

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

下载Word文档
猜你喜欢
  • 详解JS前端使用迭代器和生成器原理及示例
    目录正文for of 是干什么用的可迭代对象是什么?生成器和迭代器的关系。让非迭代对象也可以使用for of 进行遍历for循环和for in的关系总结正文 生成器和迭代器这两个东...
    99+
    2023-02-21
    JS前端迭代器生成器 JS迭代器生成器
  • JS前端使用迭代器和生成器原理是什么
    这篇文章主要介绍了JS前端使用迭代器和生成器原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JS前端使用迭代器和生成器原理是什么文章都会有所收获,下面我们一起来看看吧。正文生成器和迭代器这两个东西平时作...
    99+
    2023-07-05
  • 详解Python中迭代器和生成器的原理与使用
    目录1.可迭代对象、迭代器1.1概念简介1.2可迭代对象1.3迭代器1.4区分可迭代对象和迭代器1.5可迭代对象和迭代器的关系1.6可迭代对象和迭代器的工作机制1.7自己动手创建可迭...
    99+
    2022-11-11
  • python列表生成器常用迭代器示例详解
    目录列表生成式基础语法1. 使用列表生成式,一行解决for循环2. 双层循环3. 加判断语句,条件过滤4. 加入函数5. 常见几种迭代器:range、 zip 、 enumerate...
    99+
    2022-11-13
  • 使用redis生成唯一编号及原理示例详解
    在系统开发中,保证数据的唯一性是至关重要的一件事,目前开发中常用的方式有使用数据库的自增序列、UUID生成唯一编号、时间戳或者时间戳+随机数等。 在某些特定业务场景中,可能会要求我们...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作