JS的迭代器是啥?精读JS迭代器

这篇具有很好参考价值的文章主要介绍了JS的迭代器是啥?精读JS迭代器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

概念

优点

用法

对象迭代能力

为什么对象没有迭代器

迭代器的实现

生成器

基础语法

生成器传参

生成器委托

可终止迭代器

总结


前言

在ES6中引入了迭代器的概念,它是一种遍历数据集合的机制,提供了一种简单而一致的方式来访问集合中的每个元素,在集合与映射这篇文章中,我们就已经初步认识了Symbol.iterator这个概念。

概念

迭代器是通过迭代协议实现的,每一个拥有该协议的对象都可以称作是可迭代的对象,这个协议的标识就是Symbol.iterator,它是ES6中引入的一个新的Symbol值,表示一个对象是否有可迭代性。可迭代对象的Symbol.iterator属性是一个函数,我们称为迭代器对象,运行这个函数会返回一个next函数(next函数可以当成是JS的原型链或者C中链表的指针),运行next函数后又可以接收两个属性:value和done;value表示当前迭代的值;done表示遍历完全部迭代。

在JS中可迭代的对象有以下几种:

  1. Array(数组)
  2. Map(映射)
  3. Set(集合)
  4. String(字符串)
  5. TypedArray(类数组)
  6. NodeLists(Dom节点)

需要注意的是Object没有迭代能力

优点

  1. 灵活性:迭代器提供了一套灵活的遍历机制,使用相同的语法和操作方式于不同类型的数据结构

  2. 可迭代性:通过实现迭代器协议,可以让对象具有可迭代性,从而可以使用for of循环来遍历对象,增强代码可读性

  3. 惰性求值:迭代器是一种惰性求值的机制,只有在需要下一个元素时才会取值,这样可以节省内存,提高性能

  4. 可中断性:迭代器可以在任意时刻中断遍历,而不需要遍历整个数据结构,提高代码的效率

  5. 支持函数式编程:迭代器是函数式编程中常用的工具,它可以和其他函数式编程的特性一起使用,例如高阶函数、map、filter、reduce 等等

用法

简单介绍一下迭代器的用法,使用[Symbol.iterator]()运行迭代对象,获取next,运行next获取迭代值

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr[Symbol.iterator]().next()); // { value: 1, done: false }

我们可以借助while对数组执行遍历操作

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator = arr[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
    console.log(next.value); // 1~9
}

或者通过ES6新增的for of对迭代对象进行遍历,for of和for in类似,for in是遍历索引,for of是遍历属性值

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for (const iterator of arr) {
    console.log(iterator);
}

对象迭代能力

为什么对象没有迭代器

对象是一种无序的集合类型,与数组或类数组不同,它的属性名称是字符串或Symbol类型,并且不具备索引。因此对象不能像数组一样使用简单的循环结构来遍历属性值,而是需要通过一些特殊的方法来实现对象的迭代。

迭代器的实现

基于上面的用法,我们可以尝试在对象上实现迭代器

Reflect.defineProperty(Object.prototype, Symbol.iterator, {
    value: function () {
        const keys = Reflect.ownKeys(this).filter(it => it !== Symbol.iterator) // 过滤自身
        const len = keys.length
        let count = 0
        return {
            next: () => ({ value: this[keys[count++]], done: count > len })
        }
    }
})

可以看到,对象像迭代对象一样也可以通过迭代的方式获取到值

const obj: any = {
    name: "阿黄",
    age: 10,
    like: "meat"
}
const iterator = obj[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
    console.log(next.value); // 阿黄 10 meat
}

for (const iterator of obj) {
    console.log(iterator); // 阿黄 10 meat
}

生成器

生成器(Generator)是 ES6 中新增的一种特殊函数,它的语法与迭代器有共同之处,可以看作是一种特殊的迭代器,它通过function*关键字来定义。生成器函数的内部可以使用yield关键字来暂停函数的执行,并返回执行结果,同时也可以再次从暂停的位置开始执行。在函数外部使用next()函数来获取生成器的迭代值,结构与上面的迭代器相同,包含value和done值

基础语法

比如,我们使用一个数组来表示函数异步的内容,在内部使用yield对函数进行暂停操作,在外部使用generator.next()对内部暂停的结果取迭代值

function* start(list: any[]) {
    let i = list.length
    while (i-- >= 0) {
        yield list[i]
    }
}
const arr = [1, 2, 3, 4, 5]
const generator = start(arr)
let next
while (next = generator.next(), !next.done) {
    console.log(next.value); // 5~1
}

生成器传参

在next函数中传入参数可以将参数带入生成器函数中,比如

function* start(q1: string) {
    const name: string = yield q1
    yield `我叫${name}`
}
const generator = start("你叫什么名字")
console.log(generator.next().value);// 你叫什么名字
console.log(generator.next("张三").value);// 我叫张三

生成器委托

生成器之间可以使用yield*关键字进行传递,函数中的多个生成器会连接在一起,一起输出值

function* getName(name: string) {
    yield `我叫`
    yield `${name}`
}
function* getAge(age: number) {
    yield `我${age}了`
}
function* getInfo(__name: string, __age: number) {
    yield* getName(__name)
    yield* getAge(__age)
}
const generator = getInfo("张三", 20)
console.log(generator.next().value);// 我叫
console.log(generator.next().value);// 张三
console.log(generator.next().value);// 我20了

上面的getInfo等同于

function* getInfo(__name: string, __age: number) {
    yield `我叫`
    yield `${__name}`
    yield `我${__age}了`
}

可终止迭代器

可终止迭代器在ES6中并未正式加入,但是却有相关的声明,使用return函数可以跳出迭代。使用throw函数可以跳出迭代并抛错,所以我们可以借助上面的对象迭代器的方式,实现一个迭代终止的功能

首先我们实现一个数组的迭代器,数组和对象区别在于已经存在length属性,所以我们做个兼容就行了

Reflect.defineProperty(Array.prototype, Symbol.iterator, {
    value: function () {
        const keys = Reflect.ownKeys(this).filter(it => it !== Symbol.iterator) // 过滤自身
        const len = this.length ?? keys.length
        let count = 0
        return {
            next: () => {
                const done = count >= len
                return { value: !done ? this[keys[count++]] : void 0, done }
            },
        }
    }
})
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator = arr[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
    console.log(next.value); // 1~9
}

然后我们在迭代器中增加return函数和throw函数

throw(err?: string) {
    throw new Error(err)
},
return() {
    count = len
    return { done: true };
}

接着在数组中使用一下

return函数:

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator: any = arr[Symbol.iterator]()
console.log(iterator.next());// { value: 1, done: false }
iterator.return()
console.log(iterator.next());// { value: undefined, done: true }

 throw函数:

console.log(iterator.next());// { value: 1, done: false }
iterator.throw("抛个错")// Error: 抛个错

总结

本文介绍了JS迭代器的概念以及用法,并使用反射机制在Object中实现了迭代器,此外,生成器是特殊的迭代器,它的使用与迭代器类似,最后实现了迭代器中的可终止迭代器,使迭代器拥有终断功能

以上就是全部内容了,感谢你的阅读,如果觉得文章不错的话,还望支持一下博主,谢谢~文章来源地址https://www.toymoban.com/news/detail-563614.html

到了这里,关于JS的迭代器是啥?精读JS迭代器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【js Set()】

    Set() 是 JavaScript 中的数据结构之一,它类似于数组,但是每个值都是唯一的(没有重复的值)。它可以存储任何类型的值,包括原始类型和对象引用。 创建一个 Set 对象的语法如下: 或者可以传递一个数组或类数组对象来初始化 Set 对象: Set() 对象具有以下方法: add(value):

    2024年02月15日
    浏览(27)
  • JS数据结构——Set(集合)详解

    参考: 阮一峰 ECMAScript 6 (ES6) 标准入门教程 Set类似于数组,但是成员的值都是唯一的,没有重复的值。 也就是说它是一系列无序,没有重复数值的数据集合。 很多时候我们把Set叫做集合,但是,Set可以是集合,集合不一定是Set。 Set可以添加数组,因为没有重复数据的特性,

    2024年02月04日
    浏览(30)
  • JS中的Map、Set、WeakMap和WeakSet

    在JavaScript中,Map、Set、WeakMap和WeakSet是四个不同的数据结构,它们都有不同的特点和用途: 1. Map :Map是一种键值对的集合,其中的键和值可以是任意类型的。与对象类似,它们可以通过键来访问值。不同之处在于,Map可以使用任意类型作为键,而对象只能使用字符串或Symb

    2023年04月26日
    浏览(30)
  • 【JS】如何解决Cannot set properties of undefined

    TypeError: Cannot set properties of undefined 类型错误:无法设置未定义的属性 问题解析 当前的是当前对象或者数组是undefined,但是却用来引用属性或者索引 比如下面两种情况 或者是当前的value值不是我们显式声明的undefined,而是运算之后得到undefined,之后我们再去用它 解决方案 问

    2024年02月16日
    浏览(65)
  • JS中, Set为什么是带键的集合?

    为了降低并发时的API请求量, 这两天写了个LRU Cache. 其中用到了Set做AllowList, 来判断API是否应该被缓存. 在MDN查API时, 发现Set被归类在Keyed Collection中. 一直以来, 下意识觉得Set只是value唯一的Array. 应该属于Indexed Collection. 感觉有些奇怪, 所以就查了下Set的实现机制 一开始, 先去MD

    2024年02月08日
    浏览(35)
  • 【迭代器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

    迭代器模式(Iterator Pattern),是一种结构型设计模式。给数据对象构建一套按顺序访问集合对象元素的方式,而不需要知道数据对象的底层表示。 迭代器模式是与集合共存的,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像Java中的Collection,List、Set、Map等

    2023年04月17日
    浏览(49)
  • 【Anime.js】——JavaScript动画库:Anime.js——学习笔记

    目录 一、搭建开发环境  二、基本功能和使用 开始制作动画 动画属性 三、anime.stagger——交错动画 四、timeline——时间轴  五、控制、回调与助手 一、控制  二、回调 三、助手 六、easings——动画运动曲线 七、SVG动画 官网定义: anime.js 是一个简便的JS动画库,用法简单而

    2024年02月01日
    浏览(44)
  • JavaScript:解决计算精度问题/mathjs/bignumber.js/big.js/decimal.js

    一、计算精度现象举例 举例1、加法 举例2、减法    举例3、乘法 举例3、除法 二、JS为什么会有计算精度的问题 JavaScript 内部只有一种数字类型Number,也就是说,JavaScript 语言的底层根本没有整数,所有数字都是以IEEE-754标准格式64位浮点数形式储存,1与1.0是相同的。因为有

    2024年02月10日
    浏览(42)
  • JS常见报错解决办法:Uncaught TypeError: Cannot set properties of null (setting ‘innerHTML‘)

    Uncaught TypeError: Cannot set properties of null (setting ‘innerHTML’)意思是, 未捕获类型错误:无法设置空属性(设置“innerHTML”), 也就是说**.innerHTM**前的对象内容是空或null。 1、举个例子,我需要用js渲染HTML网页的数据。 报错: Uncaught TypeError: Cannot set properties of null (setting ‘in

    2024年02月16日
    浏览(50)
  • 【JS】js数组分组,javascript实现数组的按属性分组

    项目代码中有很多时候需要按一定的条件实现按属性分组 你可以使用JavaScript的 Array.prototype.reduce() 方法来将数组分组。这是一种高级的方法,它可以将数组元素组合成一个单值。在这种情况下,你可以使用它来把数组元素放到一个对象中,其中对象的键是分组的条件,值是所

    2023年04月08日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包