lodash源码分析之compact中的遍历

2023-05-16

小时候,

乡愁是一枚小小的邮票,

我在这头,

母亲在那头。

长大后,乡愁是一张窄窄的船票,

我在这头,

新娘在那头。

后来啊,

乡愁是一方矮矮的坟墓,

我在外头,

母亲在里头。

而现在,

乡愁是一湾浅浅的海峡,

我在这头,

大陆在那头。

——余光中《乡愁》

本文为读 lodash 源码的第三篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

gitbook也会同步仓库的更新,gitbook地址:pocket-lodash

作用与用法

compact 函数用来去除数组中的假值,并返回由不为假值元素组成的新数组。

falsenull0""undefinedNaN 都为假值。

例如:

var arr = [1,false,2,null,3,0,4,NaN,5,undefined]
_.compact(arr) // 返回 [1,2,3,4,5]

源码

function compact(array) {
  let resIndex = 0
  const result = []

  if (array == null) {
    return result
  }

  for (const value of array) {
    if (value) {
      result[resIndex++] = value
    }
  }
  return result
}

compact 的源码只有寥寥几行,相当简单。

首先判断传入的数组是否为 null 或者 undefined,如果是,则返回空数组。

然后用 for...of 来取得数组中每项的值,如果不为假值,则存入新数组 result 中,最后将新数组返回。

到这里,源码分析完了。

但是在看源码的时候,发现这里用了 for...of 来做遍历,其实除了 for...of 外,也可以用 for 或者 for...in 来做遍历,那为什么最后选了 for...of 呢?

数组中的for循环

使用 for 循环,很容易就将 compact 中关于循环部分的源码改写成以下形式:

for (let i = 0; i < array.length; i++) {
    const value = array[i]
    if (value) {
      result[resIndex++] = value
    }
  }

这样写,肯定是没有问题的,但是不够简洁。

for…in

再来看 for...in 循环,先来将源码改写一下:

for (let index in array) {
  const value = array[i]
  if (value) {
    result[resIndex++] = value
  }
}

先看看MDN上关于 for...in 的用法:

for…in语句以任意顺序遍历一个对象的可枚举属性。

关于可枚举属性,可以点击上面的链接到MDN上了解一下,这里不做太多的解释。

在数组中,数组的索引是可枚举属性,可以用 for...in 来遍历数组的索引,数组中的稀疏部分不存在索引,可以避免用 for 循环造成无效遍历的弊端。

但是,for...in 有两个致命的特性:

  1. for...in 的遍历不能保证顺序
  2. for...in 会遍历所有可枚举属性,包括继承的属性。

for...in 的遍历顺序依赖于执行环境,不同执行环境的实现方式可能会不一样。单凭这一点,就断然不能在数组遍历中使用 for...in,大多数情况下,顺序对于数组的遍历都相当重要。

关于第二点,先看个例子:

var arr = [1,2,3]
arr.foo = 'foo'
for (let index in arr) {
  console.log(index)
}

在这个例子中,你期望输出的是 0,1,2,但是最后输出的可能是 0,1,2,foofor...in 不能保证顺序)。因为 foo 也是可枚举属性,在 for..in 会被遍历出来。

for…of

最后来看看 for...of

当我们在控制台中打印一个数组,并将它展开来查看时,会在数组的原型链上发现一个很特别的属性 Symbol.iterator

其实 for...of 循环内部调用的就是数组原型链上的 Symbol.iterator 方法。

Symbol.iterator 在调用的时候会返回一个遍历器对象,这个遍历器对象中包含 next 方法,for...of 在每次循环的时候都会调用 next 方法来获取值,直到 next 返回的对象中的 done属性值为 true 时停止。

其实我们也可以手动调用来模拟遍历的过程:

const arr = [1,2,3]
const iterator = a[Symbol.iterator]()
iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // {value: undefined, done: true}

知道这些原理后,完全可以改写数组中的 Symbol.iterator 方法,例如遍历时将数组中的值都乘2:

Array.prototype[Symbol.iterator] = function () {
  let index = 0
  const _self = this
  return {
    next: function () {
      if (index < _self.length) {
        return {value: _self[index++] * 2, done: false}
      } else {
        return {done: true}
      }
    }
  }
}

使用 Generator 函数可以写成以下的形式:

Array.prototype[Symbol.iterator] = function* () {
  let index = 0
  while (index < this.length) {
    yield this[index++] * 2   
  }
}

因此在不改写 Symbol.iterator 的情况下,使用 for...of 来遍历数组是安全的,因为这个方法是数组的原生方法。

关于 IteratorGenerator 可以点击参考中的链接详细查看。

参考

  1. MDN:迭代器和生成器
  2. Iterator 和 for…of 循环
  3. Generator 函数的语法
  4. Lodash源码讲解(3)-compact函数
  5. MDN:for…of
  6. MDN:for…in

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

lodash源码分析之compact中的遍历 的相关文章

  • 根据第二个数组中的值过滤对象数组

    我有一个对象数组 我想根据任何键的值是否与另一个数组中的任何值匹配来过滤它以创建一个新数组 const array1 name pink id 13 name orange id 17 name red id 64 name purple
  • JavaScript:使值对数组形成值数组

    有没有一种优雅 实用的方法来转换这个数组 1 5 9 21 进入这个 1 5 5 9 9 21 我知道我可以forEach数组并收集值以创建一个新数组 有没有一种优雅的方式来做到这一点 lodash不使用forEach 您可以映射一个拼接数
  • 如何在javascript中从数组中删除重复的对象?

    在我的代码中 我创建了一个名为 array1 的数组 在这个数组中我列出了多个对象 我想过滤掉 array1 对象值作为唯一 并且需要将 id 与其各自的值分组 我在这里添加了我的代码 Array1 var array1 value A i
  • lodash:如何压缩具有值的对象数组

    我正在研究如何使用 lodash 压缩具有值的对象数组 包括每个值的新键 尝试过zip https lodash com docs zip zip对象 https lodash com docs zipObject and map http
  • 如何使用 JavaScript (lodash) 深度映射对象键?

    https lodash com docs mapKeys https lodash com docs mapKeys 是否可以使用 Lodash 深度映射对象的键 如果没有 是否有另一个库提供此功能 如果与其他深度迭代和操作功能组合在一起
  • 如何在 TypeScript 中使用 lodash.mixin

    我的团队正在评估将一些文件从 JavaScript 切换到 TypeScript 并且我们在代码中广泛使用了一些自定义 mixin 方法 从一些基本测试来看 虽然我们可以使用 mixin 按照规范创建 mixin 但我们无法在不出现编译错误
  • 我有两个数组,如何找到匹配的元素并执行某些操作? (洛达什)

    var array1 Age 24 Name Test StudentID 101 Checked false Age 25 Name Test StudentID 102 Checked false var array2 ID 101 如
  • 使用 LoDash 合并包含相同键/值的对象

    在对初始数组中的 LoDash 进行一些操作后 我最终得到以下结果 number 3 product apple number 2 product apple number 4 product pear 我怎样才能操纵它最终得到 numbe
  • 使用 lodash 在另一个数组内的数组中查找值

    我有一个数组 例如 var db words word1a word1b word1c answer answer1 words word2a words2b answer answer2 我在 node js 上使用 lodash 来检查
  • 使用 lodash 的 isEqual() 在比较中排除一些属性

    我在用 是平等的 https lodash com docs isEqual它比较 2 个对象数组 例如 每个对象 10 个属性 并且工作正常 现在有 2 个属性 创建和删除 我不需要成为比较的一部分 Example var obj1 na
  • 从对象中的所有键中删除字符 (Lodash OK)

    在这个对象的所有键之前 我有一个令人烦恼的字符长度 由于它们都是相同的 我想做一个 map or forEach 或带有 slice 在其中删除第一个n人物 如何对对象中的所有键执行此操作 我应该说我们已经在项目中导入了 Lodash 所以
  • 如何在 React Query 中将 debounce 与 useQuery 一起使用?

    我正在使用 React Query 从 React 应用程序中的 API 获取数据 我想实现去抖以获得更好的性能 但我无法让它与 useQuery 一起使用 当我尝试将 API 调用包装在去抖函数中时 收到一条错误消息 查询函数必须返回定义
  • 使用 Lodash 省略嵌套属性

    我正在尝试摆脱这些属性5MinuteRate and 15MinuteRate在以下对象中 var object requestsPerSecond mean 1710 2180279856818 count 10511 currentRa
  • 如何合并对象数组?

    假设我有一系列文章 每篇文章可能有也可能没有超过 1 个图像对象 现在由于 mysql 无法将对象分组在一起 所以你必须自己做 所以结果是你得到near重复的文章对象 唯一的区别是图像对象 By near重复我的意思是返回结果的唯一区别是图
  • 使用 JavaScript 将对象的特定属性合并在一起

    所以我有一个像这样的对象数组 name Joe Smith job Custodian age 35 id 3421 name George Henderson job CEO age 43 id 5098 name Joe Smith j
  • Angular 2 - 消除 keyUp 事件的抖动

    如何消除在 keyUp 事件上调用的函数 这是我的代码 我的功能 private handleSearch searchTextValue string skip number void this searchTextValue searc
  • Javascript:将值返回给回调函数外部的变量[重复]

    这个问题在这里已经有答案了 我有一个非常具体的问题 希望有人可以帮助我 我对 Javascript 很陌生 对 NodeJS 则更陌生 我在用lodash s forIn遍历并添加到数组内的对象的功能 整个事情看起来是这样的 id 20 k
  • 如何按嵌套属性对数组进行排序

    let array id 248439 name Cross Creek Ranch Creek Cove surveyStatus territoryName Fulshear subdivisionName Cross Creek Ra
  • 当数据未定义或为空时如何使用 Lodash

    在我的应用程序中 如果来自服务的数据未定义或为 null 我的 html 将无法加载 并且会收到 数据未定义 错误 所以我尝试使用lodash 但不知道如何使用它 在我下面的 ts 文件中 this PartService GetDataV
  • 使用 Lodash 循环 JavaScript 对象中的属性

    是否可以循环访问 JavaScript 对象中的属性 例如 我有一个 JavaScript 对象定义如下 myObject options property1 value 1 property2 value 2 属性将动态添加到该对象 有没

随机推荐

  • J2EE技术规范(七)——JTA(理解JTA,编写简单的事务客户程序)

    之前的内容中 xff0c 写了几篇关于J2EE规范的博客 xff0c 现在继续来完善这些内容 xff0c 这次内容主要补充上一篇博客 WebLogic Server使用JTA1 0 1a实现和管理事务 WebLogic Server提供以下
  • J2EE技术规范(八)——JMS(消息,域)

    老样子 xff0c 继续完善J2EE技术规范 xff0c 这次内容主要是写个JMS 理解面向消息的中间件 定义 xff1a 消息 xff08 1 xff09 消息是可编程实现两端通信的机制 xff08 2 xff09 一些消息技术如 xff
  • J2EE技术规范(九)——JMS (JMS客户端)

    上篇博客写了JMS的一些内容 xff0c 后来觉得那篇博客的内容不够阐述JMS的内容 xff0c 所以这篇博客就继续完善JMS 在WebLogic Server 环境中配置JMS WebLogic Server的JMS特性 WebLogic
  • ubuntu下载搜狗输入法并设置开机自启动

    官网下载搜狗输入法linux版deb包 下好后在下载目录里执行安装 xff1a sudo dpkg i sogoupinyin 3 4 0 9700 amd64 deb 因为我之前下载过搜狗输入法 xff0c 卸掉后fcitx输入法系统还在
  • Java基础之抽象类与接口

    很多常见的面试题都会出诸如抽象类和接口有什么区别 xff0c 什么情况下会使用抽象类和什么情况你会使用接口这样的问题 本文我们将仔细讨论这些话题 在讨论它们之间的不同点之前 xff0c 我们先看看抽象类 接口各自的特性 抽象类 抽象类是用来
  • debian系linux更新时,提示“由于没有公钥,无法验证下列签名”

    问题 在新安装的Ubuntu上 xff0c 我在使用sudo apt get update更新时 xff0c 出现如下错误 xff1a W GPG error http mirrors span class hljs number 163
  • 机器学习(周志华) 第八章集成学习

    关于周志华老师的 机器学习 这本书的学习笔记 记录学习过程 本博客记录Chapter8 1 个体与集成 集成学习 xff08 ensemble learning xff09 xff1a 通过构建多个学习器来完成学习的任务 可以分成同质集成
  • MWC(1) Multiwii 飞控程序初学者概要

    学习MWC飞控程序有一段时间了 xff0c 略有所得 xff0c 现整理一下学习思路 xff0c 略作记录 大三开始老师让我看飞控程序 xff0c 就给了一块飞控板 xff08 如下图 xff09 xff0c Cirus AIOP xff0
  • 我们约会吧魏荔嵩 不要迷恋姐,姐容易让你胃出血

    魏荔嵩是 我们约会吧 20101229期的女嘉宾 xff0c 来自上海 xff0c 家乡是内蒙古呼伦贝尔的 xff0c 27岁的魏荔嵩是一名广告策划 xff0c 曾是一名白衣天使 魏荔嵩的世纪佳缘昵称 xff1a 粉红小猪 太嗲了 xff0
  • MWC(2) Multiwii初学者详细准备

    1 1 软件准备 Arduino IDE 官方下载链接 xff1a https www arduino cc download handler php 或者Arduino社区资源 xff1a http www arduino cn thre
  • Linux(Ubuntu)下使用OneNote

    开始学习ROS xff0c 学习时遇到问题想要记录 xff0c 原来Office套件不支持Linux xff0c 大坑一 xff1a 搜了很久 xff0c 看到的无外乎以下几种 xff1a 作者 xff1a mst7 链接 xff1a ht
  • Ubuntu Anaconda 安装tensorflow及opencv3.2.0

    教程已更新 xff0c 请参照http blog csdn net yjy728 article details 78826447 一 安装Anaconda windows只支持python3 5 X xff0c ubuntu下直接下最新版
  • Ubuntu16.04下PX4 开发环境配置

    PX4 Ubuntu1604 开发环境配置 问题1 依赖错误及安装时404错误问题2 安装基于NuttX的硬件出错问题3 编译报错问题4 QT配置问题 PX4 Ubuntu16 04 开发环境配置 看到官网有详细介绍 xff08 官网安装说
  • [px4仿真]单独启动编译和Gazebo仿真器

    This article shows how to starting Gazebo and PX4 separately 按照官方教程并没有成功 中文教程和英文教程都有错误 xff0c 应该如下 span class hljs built
  • [px4仿真]px4的STIL仿真中添加向下的摄像头

    后面发现这样改有问题 xff0c 正确的修改方法参考这条提交记录 xff1a https github com TokyoClod sitl gazebo commit e61e6e46a665804f072474b2b1b085fb701
  • VISP库IBVS仿真

    示例程序1 tutorial ibvs 4pts cpp span class hljs comment example tutorial ibvs 4pts cpp span span class hljs preprocessor in
  • blender中UV贴图及导出dae文件

    设置单位meter 设置大小 按 N调出属性面板 设置 依次选择编辑模式 线框 面选择 xff1b 进入UV贴图模式 右击选中物体上表面 xff0c 按U 展开 xff1b 上方选择UV Editing模式 贴图 左下底部选择 图像 打开图
  • AprilTag视觉定位系统

    AprilTag是一个视觉基准库 xff0c 在AR xff0c 机器人 xff0c 相机校准领域广泛使用 通过特定的标志 xff08 与二维码相似 xff0c 但是降低了复杂度以满足实时性要求 xff09 xff0c 可以快速地检测标志
  • keras 多输入多输出网络

    keras中的多输入多输出网络 多输入多输出网络搭建的官网介绍 xff1a http keras cn readthedocs io en latest getting started functional API Demo span cl
  • lodash源码分析之compact中的遍历

    小时候 xff0c 乡愁是一枚小小的邮票 xff0c 我在这头 xff0c 母亲在那头 长大后 xff0c 乡愁是一张窄窄的船票 xff0c 我在这头 xff0c 新娘在那头 后来啊 xff0c 乡愁是一方矮矮的坟墓 xff0c 我在外头