写点什么

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:191520

评论

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

重塑企业数字化能力,端点科技重磅发布Erda2.0

科技热闻

Flink 实践教程-进阶(11):SQL 关联:Regular Join

腾讯云大数据

flink 流计算 流计算 Oceanus

Improvements of Job Scheduler and Query Execution on Flink OLAP

Apache Flink

大数据 flink 编程 实时计算 OLAP

netty系列之:netty中的核心MessageToMessage编码器

程序那些事

Java Netty 程序那些事 4月月更

2022华为软件精英挑战赛复赛名单公布,快来看看都有哪些优秀赛队晋级

科技热闻

Hoo虎符研究院|从多个方面了解公链Tezos和它的 Ithaca 2 升级

区块链前沿News

Hoo 虎符交易所 研究院 tezos

Ribbon从入门到源码解析

李子捌

微服务 SpringCloud Ribbon

两步实现让antd与IDE和睦相处的处理案例

袋鼠云数栈

大数据 开源

数栈在湖仓一体上的探索与实践

袋鼠云数栈

数据库 大数据 数据湖 湖仓一体

恒源云(Gpushare)_如何安装包/pip加速等?技巧大放送3!

恒源云

安装 pip Ubuntu apt

打通产销对接,构建新型数智化农副产品供应链

数商云

产业互联网 数字化

Spring 完美导入 IDEA

阿Q说代码

spring IDEA 4月月更

腾讯云CDW-ClickHouse云原生实践

腾讯云大数据

Clickhouse 云数据仓库

龙蜥开源Plugsched:首次实现 Linux kernel 调度器热升级 | 龙蜥技术

OpenAnolis小助手

Linux 内核 龙蜥社区 Plugsched

RabbitMQ 实现延时队列(订单定时取消为例)

Ayue、

Rabbit MQ 4月月更

ffmpeg实现web在线转码

lo

4月月更

一个公式告诉你:如何提升团队的研发效率?

凌晞

技术管理 研发效率

恒源云(Gpushare)_JupyterLab/TensorBoard使用问题?技巧大放送4!

恒源云

人工智能 深度学习 PyTorch

恒源云(Gpushare)_没有你想要的镜像?技巧大放送5!

恒源云

镜像仓库 显卡、gpu

GaussDB(for Redis)助力《余烬风暴》实力上线,给您沉浸式魔幻体验

华为云数据库小助手

GaussDB GaussDB ( for Redis )

Flink 实践教程-入门(10):Python作业的使用

腾讯云大数据

Web 3.0的未来产业趋势

王强

Web 3.0

Kubernetes官方java客户端之四:内部应用

程序员欣宸

Kubernetes client 4月月更

衡石BI产品预置明道云数据连接器

明道云

实时数仓建设

五分钟学大数据

实时计算 4月月更

透过「人月神话」,看清软件开发问题

架构精进之路

软件开发 人月神话 4月日更 4月月更

云效制品仓库 Packages,不限容量免费用

阿里云云效

云计算 maven 阿里云 npm 制品仓库

北京市东城区赵海东副区长一行莅临博睿数据参观指导

博睿数据

阿里Maven仓库不限容量,免费用

阿里云云效

云计算 阿里云 npm Maven仓库 制品仓库

百度信誉保障服务架构全解析

百度Geek说

后端

基于 HTML+CSS+JS 的石头剪刀布游戏

海拥(haiyong.site)

html 大前端 游戏 4月月更

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