写点什么

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

评论

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

1688拍立淘图片搜索接口全攻略

tbapi

1688API 1688图片搜索接口 1688拍立淘接口

米哈游蔡浩宇新游戏:角色语音、情绪、动作实时生成;Argmax 端侧说话人分离框架:10M 大小 1 秒识别 4 分钟音频丨日报

RTE开发者社区

数智化转型不是“买硬件”,DeepSeek一体机别乱上

Alter

依赖倒置 DIP、依赖注入 DI、控制反转 IoC 和工厂模式

不在线第一只蜗牛

依赖

智能扫描助力节碳超13万吨,合合信息旗下扫描全能王“指尖减碳”写就绿色诗篇

合合技术团队

人工智能 算法 OCR 扫描全能王 #大数据

压测实战 | 微信小程序商城“双11”的压测实践

优测云服务平台

小程序 性能测试 接口测试 接口测试工具 压力测试、

YashanDB USERS_AIM表空间集管理

YashanDB

人工智能丨当AI三小时"抄作业"成真:测试工程师的护城河该往哪挖

测试人

人工智能

YashanDB表的存储空间

YashanDB

数据库 yashandb

YashanDB USERS表空间集管理

YashanDB

数据库 yashandb

YashanDB用户表空间管理

YashanDB

yashandb

MongoDB 可观测性最佳实践

观测云

mongodb

ElevenLabs 33 亿美元估值的秘密:技术驱动+用户导向的「小熊软糖」团队丨Voice Agent 学习笔记

RTE开发者社区

摆脱电子表格固有思维,采用现代化的预算管理软件

智达方通

数字转型 全面预算管理 财务管理

企业想知道,DeepSeek如何从外力变内力?

脑极体

AI

Sandisk闪迪发布首款车规级UFS 4.1存储解决方案,助力先进车载AI系统创新

极客天地

YashanDB表的闪回

YashanDB

数据库 yashandb

.NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义

秃头小帅oi

IP纯净度检测工具Scamalytics使用指南

Ogcloud

海外直播 海外社媒运营 海外IP代理 海外IP节点

社区动态 | KWDB 体验官火热招募中

KaiwuDB

招募 数据库、 KaiwuDB

腾讯云HAI | 1分钟,1元成本带你快速搭建你的专属DeepSeek,还有多场景体验操作指导

六月的雨在InfoQ

腾讯云 DeepSeek HAI应用服务器 Chatbox

Markdown 模板变量的使用

NocoBase

开源 markdown 低代码 零代码 无代码

产教融合、科教融汇激发世界级成果,西安交通大学鲲鹏昇腾科教创新孵化中心揭牌

极客天地

MySQL查询建表规范

秃头小帅oi

如何通过 Apache SeaTunnel 实现 MySQL 到 OceanBase的数据迁移同步

Apache SeaTunnel

Netty基础—Netty实现RPC服务

不在线第一只蜗牛

Netty

SvelteKit 最新中文文档教程(4)—— 表单 actions

冴羽

前端 前端开发 前端框架 Svelte SvelteKit

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