本文短小精悍,我保证。在过去的数个月里,我注意到在我审阅的 pull request 中有四个(关于数组使用的)错误经常出现。同时,我自己也会犯这些错误,因此有了这篇文章。让我们一起学习,以确保以后能正确地使用数组方法!

使用 Array.includes 替代 Array.indexOf

"如果需要在数组中查找某个元素,请使用 Array.indexOf。"

我记得在我学习 JavaScript 的课程中有类似的这么一句话。毫无疑问,这完全正确!

在 MDN 文档中,对 Array.indexOf 的描述是:返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。因此,如果在之后的代码中需要用到(给给定元素的)索引,那么 Array.indexOf 是不二之选。

然而,如果我们仅需要知道数组中是否包含给定元素呢?这意味着只是是与否的区别,这是一个布尔问题(boolean question)。针对这种情况,我建议使用直接返回布尔值的 Array.includes。

\'use strict\';

const characters = [
  \'ironman\',
  \'black_widow\',
  \'hulk\',
  \'captain_america\',
  \'hulk\',
  \'thor\',
];

console.log(characters.indexOf(\'hulk\'));
// 2
console.log(characters.indexOf(\'batman\'));
// -1

console.log(characters.includes(\'hulk\'));
// true
console.log(characters.includes(\'batman\'));
// false

使用 Array.find 替代 Array.filter

Array.filter 是一个十分有用的方法。它通过回调函数过滤原数组,并将过滤后的项作为新数组返回。正如它的名字所示,我们将这个方法用于过滤,(一般而言)会获得一个长度更短的新数组。

然而,如果知道经回调函数过滤后,只会剩余唯一的一项,那么我不建议使用 Array.filter。比如:使用等于某个唯一 ID 为过滤条件去过滤一个数组。在这个例子中,Array.filter 返回一个仅有一项的新数组。然而,我们仅仅是为了获取 ID 为特定 ID 的那一项,这个新数组显得毫无用处。

让我们讨论一下性能。为了获取所有符合回调函数过滤条件的项,Array.filter 必须遍历整个数组。如果原数组中有成千上万项,回调函数需要执行的次数是相当多的。

为避免这些情况,我建议使用 Array.find。它与 Array.filter 一样需要一个回调函数,(但只是返回)符合条件的第一项。当找到符合回调函数过滤条件的第一个元素时,它会立即停止往下的搜寻。不再遍历整个数组。

\'use strict\';

const characters = [
  { id: 1, name: \'ironman\' },
  { id: 2, name: \'black_widow\' },
  { id: 3, name: \'captain_america\' },
  { id: 4, name: \'captain_america\' },
];

function getCharacter(name) {
  return character => character.name === name;
}

console.log(characters.filter(getCharacter(\'captain_america\')));
// [
//   { id: 3, name: \'captain_america\' },
//   { id: 4, name: \'captain_america\' },
// ]

console.log(characters.find(getCharacter(\'captain_america\')));
// { id: 3, name: \'captain_america\' }

使用 Array.some 替代 Array.find

我承认我经常犯这个错误。之后,一位朋友建议我去查看 MDN 文档 以寻找更好的方法。事实上(这错误)与上面 Array.indexOf/Array.includes 的例子十分相像。

在上面的例子中,我们知道 Array.find 需要一个回调函数作为参数,并返回(符合条件的)第一个元素。然而,当我们需要知道数组中是否存在一个元素时,Array.find 是最好的选择吗?不一定是,因为它返回一个元素,而不是一个布尔值。

在下面的例子中,我建议使用 Array.some,它返回你需要的布尔值。

\'use strict\';

const characters = [
  { id: 1, name: \'ironman\', env: \'marvel\' },
  { id: 2, name: \'black_widow\', env: \'marvel\' },
  { id: 3, name: \'wonder_woman\', env: \'dc_comics\' },
];

function hasCharacterFrom(env) {
  return character => character.env === env;
}

console.log(characters.find(hasCharacterFrom(\'marvel\')));
// { id: 1, name: \'ironman\', env: \'marvel\' }

console.log(characters.some(hasCharacterFrom(\'marvel\')));
// true

译者注:补充一下 Array.some 与 Array.includes 使用上的区别。两者都返回一个布尔值,表示某项是否存在于数组之中,一旦找到对应的项,立即停止遍历数组。不同的是 Array.some 的参数是回调函数,而 Array.includes 的参数是一个值(均不考虑第二个可选参数)。

假设希望知道值为 value 的项是否存在于数组中,既可以编写代码:[].includes(value), 也可以给 Array.some 传入 item => item === value 作为回调函数。Array.includes  使用更简单,Array.some 可操控性更强。

使用 Array.reduce 替代 Array.filter 与 Array.map 的组合

事实上说,Array.reduce 不太容易理解。然而,如果我们先使用 Array.filter 过滤原数组,之后(对结果)再调用 Array.map (以获取一个新数组)。这看起似乎有点问题,是我们忽略了什么吗?

这样做的问题是:我们遍历了两次数组。第一次是过滤原数组以获取一个长度稍短的新数组,第二次遍历(译者注:指 Array.map)是对 Array.filter 的返回的新数组进行加工,再次创造了一个新数组!为得到最终的结果,我们结合使用了两个数组方法。每个方法都有它自己的回调函数,而且供 Array.map 使用的临时数组是由 Array.filter 提供的,(一般而言)该数组无法复用。

为避免如此低效场景的出现,我的建议是使用 Array.reduce 。一样的结果,更好的代码!Array.reduce 允许你将过滤后切加工过的项放进累加器中。累加器可以是需要待递增的数字、待填充的对象、 待拼接的字符串或数组等。

在上面的例子中,我们使用了 Array.map,(但更)建议使用累加器为待拼接数组的 Array.reduce 。在下面的例子中,根据变量 env 的值,我们会将它加进累加器中或保持累加器不变(即不作任何处理)。

\'use strict\';

const characters = [
  { name: \'ironman\', env: \'marvel\' },
  { name: \'black_widow\', env: \'marvel\' },
  { name: \'wonder_woman\', env: \'dc_comics\' },
];

console.log(
  characters
    .filter(character => character.env === \'marvel\')
    .map(character => Object.assign({}, character, { alsoSeenIn: [\'Avengers\'] }))
);
// [
//   { name: \'ironman\', env: \'marvel\', alsoSeenIn: [\'Avengers\'] },
//   { name: \'black_widow\', env: \'marvel\', alsoSeenIn: [\'Avengers\'] }
// ]

console.log(
  characters
    .reduce((acc, character) => {
      return character.env === \'marvel\'
        ? acc.concat(Object.assign({}, character, { alsoSeenIn: [\'Avengers\'] }))
        : acc;
    }, [])
)
// [
//   { name: \'ironman\', env: \'marvel\', alsoSeenIn: [\'Avengers\'] },
//   { name: \'black_widow\', env: \'marvel\', alsoSeenIn: [\'Avengers\'] }
// ]

这就是本文的全部内容!

希望这对你有帮助。如果你对本文有任何意见或(关于数组方法使用的)例子需要讨论,请在评论中告诉我。如果你觉得本文不错,请给我点赞 ? (译者注:对灯发誓,这是原文,不是译者骗赞!)并分享给更多的小伙伴。感谢你的阅读!

PS: 你可以在 Twitter 上关注我 。

注意:请在使用 Array.find 和 Array.includes 前检查浏览器是否支持相关方法,上述两个方法在 Internet Explorer 上并不支持(译者注:可以使用 Polyfill)。

本文转载自【前端猿媛】

英文:pacdiv  译文:sea_ljf

https://juejin.im/post/5b8d0a74f265da431d0e7ec

如何在 JavaScript 中更好地使用数组相关推荐

  1. javascript字典中添加数组_如何在 JavaScript 中更好地使用数组

    在 freeCodeCamp 社区阅读原文. 本文短小精悍,我保证.在过去的数个月里,我注意到在我审阅的 pull request 中有四个(关于数组使用的)错误经常出现.同时,我自己也会犯这些错误, ...

  2. javascript编写_如何在JavaScript中使用解构来编写更简洁,功能更强大的代码

    javascript编写 by Ashay Mandwarya ?️?? 由Ashay Mandwarya提供吗? 如何在JavaScript中使用解构来编写更简洁,功能更强大的代码 (How to ...

  3. 如何在JavaScript中比较数组?

    本文翻译自:How to compare arrays in JavaScript? I'd like to compare two arrays... ideally, efficiently. 我 ...

  4. 如何在javascript中使用多个分隔符分割字符串?

    如何在JavaScript中使用多个分隔符拆分字符串? 我正在尝试在逗号和空格上进行拆分,但是AFAIK,JS的拆分功能仅支持一个分隔符. #1楼 对于那些想要在拆分功能中进行更多自定义的人,我编写了 ...

  5. 如何在JavaScript中验证电子邮件地址

    如何在JavaScript中验证电子邮件地址? #1楼 与squirtle相比 ,这是一个复杂的解决方案,但是在正确验证电子邮件方面做得非常出色: function isEmail(email) { ...

  6. 现在JavaScript日期–如何在JavaScript中获取当前日期

    Many applications you build will have some sort of a date component, whether it's the creation date ...

  7. 如何在JavaScript中区分深层副本和浅层副本

    by Lukas Gisder-Dubé 卢卡斯·吉斯杜比(LukasGisder-Dubé) 如何在JavaScript中区分深层副本和浅层副本 (How to differentiate betw ...

  8. vj节点_创意编码—如何在JavaScript中创建VJ引擎

    vj节点 by George Gally 通过乔治·加利 创意编码-如何在JavaScript中创建VJ引擎 (Creative Coding - How to create a VJ engine ...

  9. 如何在JavaScript中使用apply(?),call(?)和bind(➰)方法

    by Ashay Mandwarya ?️?? 由Ashay Mandwarya提供吗? 如何在JavaScript中使用apply(?),call(?)和bind(➰)方法 (How to use ...

最新文章

  1. 【ThinkPHP3.2.3】学习ThinkPHP笔记:框架中的配置文件(3)
  2. ajax判断密码是否一致,jquery.validate ajax方式验证密码是否正确
  3. animateWithDuration
  4. 使用svnsync同步svn
  5. 亚麻纤维截面形态_纺织品知识点--纺织纤维的分类get
  6. HTML5 device access 设备访问
  7. Android4.4之Camera2预览流程APP到Driver(十四)
  8. 初始化audio失败是什么意思_DirectXAudio初始化失败,高手看 – 手机爱问
  9. 迁移进行时,告别GitHub的时候到了?
  10. (Python)从零开始,简单快速学机器仿人视觉Opencv---运用三:物体运动跟踪
  11. android免root读写u盘最新方法,支持安卓Q+
  12. 逸创云客服获“金耳唛杯”年度中国最佳客户中心技术产品奖
  13. 技术学院技能发展网络在线技能培训在线技能Rtaj比赛进行到一乔
  14. 红旗linux系统服务器,红旗linux11系统
  15. 【解决】json字符串解析失败json.decoder.JSONDecodeError
  16. 观护帮教之“禁毒防艾”课堂
  17. MySQL安装图解过程
  18. 因计算机丢失shw32.dll,midas.dll
  19. Prometheus监控机配置说明
  20. java11纳秒时间的局限性

热门文章

  1. linux脚本转换exe,Ps1 To Exe(powershell脚本转换EXE工具) V3.0.6 官方版
  2. 用python编写表达式求值_用Python3实现表达式求值
  3. face alignment by 3000 fps系列学习总结
  4. C++定义隐式转换函数,将类转换为内部的一个成员变量
  5. powerquery mysql数据库_window 10 下 --excel | power query 通过 ODBC链接 mysql 数据库
  6. 蔻驰和mk哪个更大牌_mk和coach哪个好?mk和coach包包是一个档次吗?
  7. 表示自己从头开始的句子_微信拍一拍后缀幽默回复有趣的句子 拍了拍唯美内容文案...
  8. 计算机常用数制转换说课稿,进制与进制转换说课稿
  9. 选择排序法对数组进行排序
  10. Shiro安全框架入门篇