写点什么

JavaScript 中 Array 方法的正确打开方式

  • 2018-09-16
  • 本文字数:2480 字

    阅读完需:约 8 分钟

在过去的几个月,我发现我的拉取请求中存在四个完全相同的 JavaScript 错误。于是我写了这篇文章,总结了如何在 JavaScript 中正确使用地使用 Array 的方法!

用 Array.includes 代替 Array.indexOf

“如果你要在数组中查找元素,请使用 Array.indexOf”。我记得在学习 JavaScript 的时候,在教材中读到这样的一句话。毫无疑问,这句话是真的!

MDN 文档写道,Array.indexOf 将“返回第一次出现给定元素的索引”。因此,如果我们稍后要在代码中使用这个返回的索引,那么使用 Array.indexOf 找到索引就对了。

但是,如果我们只想知道数组是否包含某个值,该怎么办?这似乎是一个是与否的问题,或者说是一个布尔值问题。对于这种情况,我建议使用返回布尔值的 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 是一个非常有用的方法。它接受一个回调函数作为参数,基于一个包含所有元素的数组创建出一个新的数组。正如它的名字一样,我们使用这个方法来过滤元素,获得更短的数组。

但是,如果回调函数只能返回一个元素,那么我就不推荐使用这个方法,例如使用回调函数来过滤唯一 ID。在这种情况下,Array.filter 将返回一个只包含一个元素的新数组。我们的意图可能是通过查找特定的 ID 找到数组中包含的唯一值。

我们来看看这个方法的性能。要返回与回调函数匹配的所有元素,Array.filter 必须遍历整个数组。此外,我们假设有数百个元素可以满足回调参数,那么过滤后的数组会非常大。

为了避免这种情况,我建议使用 Array.find。它需要一个像 Array.filter 一样的回调函数作为参数,并返回满足回调函数的第一个元素的值。此外,只要找到第一个满足回调函数的元素,Array.find 就会停止,无需遍历整个数组。通过 Array.find 来查找元素,我们可以更好地理解我们的意图。

复制代码
'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,它返回所需的布尔值。另外,从语义上看,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.reduce 而不是链接 Array.filter 和 Array.map

让我们面对现实吧,Array.reduce 不容易理解。事实确实如此!但是,如果我们使用 Array.filter 和 Array.map 的组合,感觉缺少了什么,对吧?

我的意思是,我们遍历了两次数组。第一次过滤数组并创建一个较短的数组,第二次又基于 Array.filter 获得数组创建一个包含新值的数组。为了获得我们想要的新数组,我们使用了两个 Array 方法。每个方法都有自己的回调函数和一个用不到的数组——由 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'] }
// ]

查看英文原文: https://medium.freecodecamp.org/heres-how-you-can-make-better-use-of-javascript-arrays-3efd6395af3c

感谢覃云对本文的审校。

2018-09-16 06:191394

评论

发布
暂无评论
发现更多内容

如何将应用一键部署至多个环境?丨Walrus教程

SEAL安全

MySQL 运维 应用部署 Walrus

一文读懂私网解析 PrivateZone

火山引擎边缘云

DNS DNS服务器 DNS劫持 #DNS

大咖公开课 | 探索AI的边界:如何精准地测试人工智能

霍格沃兹测试开发学社

提升团队效能:如何与下属进行有效沟通

霍格沃兹测试开发学社

印度股票交易系统搭建GangGuHK

GangguHK

Shell 检查程序进程是否存在,自动重启

最爱小胖子

LLM 大模型框架 LangChain 可观测性最佳实践

心有千千结

观测云 LLM langchain

云服务和本地部署大对比,应该选择哪种方式?

Finovy Cloud

云计算 云服务器 云部署搭建

✅日活3kw的实际库存业务场景中的超卖到底怎么解决的

派大星

电商超卖 互联网+ 秒杀系统架构

一键Run带你体验扩散模型的魅力

华为云开发者联盟

人工智能 华为云 华为云ModelArts 华为云开发者联盟

管理技巧 | 提升团队效能:如何与下属进行有效沟通

测吧(北京)科技有限公司

测试

探索AI的边界:如何精准地测试人工智能

测试人

软件测试

基于 TiCDC 创建灾备和容灾切换

TiDB 社区干货传送门

管理与运维 新版本/特性解读 数据库架构设计 6.x 实践 7.x 实践

TiDB Binlog功能使用实践

TiDB 社区干货传送门

6.x 实践

【我和 TiDB 社区的故事】我与 TiDB 专栏的故事

TiDB 社区干货传送门

人物访谈

3月9日(本周六)TiDB 社区活动在深圳!一起聊聊 TiDB 在零售、互联网+、Saas、游戏、出海企业的分布式数据库选型、升级降本之路、7.5 新版本的探索!线下参会有机会获得多款社区新周边哦~

TiDB 社区干货传送门

社区活动

春天已至,见证80/90/00后女性开发者的云上生长力量

华为云开发者联盟

人工智能 华为云 科技 华为云开发者联盟 先锋开发者云上说

深度解析:小红书笔记详情API的背后逻辑

技术冰糖葫芦

API 接口

国家科技传播中心讲坛!播出预告:吴甜——当机器学会思考

飞桨PaddlePaddle

人工智能 深度学习 百度 BAIDU 百度飞桨

深入浅出:JavaScript 中 every() 的运作原理

Apifox

JavaScript 程序员 前端 数组 前端开发

理解BS期权定价

数新网络官方账号

Python 期权 金融

TiKV 组件内 GC(物理空间回收)原理及常见问题

TiDB 社区干货传送门

监控 性能调优 集群管理 故障排查/诊断 TiKV 底层架构

7.1 版本 DRAutoSync 非计划内切换小记

TiDB 社区干货传送门

集群管理 数据库架构设计 7.x 实践

软件测试团队管理技巧 | 提升团队效能:如何与下属进行有效沟通

测试人

软件测试

探索AI的边界:如何精准地测试人工智能

测吧(北京)科技有限公司

测试

JavaScript中Array方法的正确打开方式_JavaScript_pacdiv_InfoQ精选文章