4个错误使用JavaScript数组方法的案例

简介: 译者按: 做一个有追求的工程师,代码不是随便写的!原文: Here’s how you can make better use of JavaScript arrays译者: Fundebug为了保证可读性,本文采用意译而非直译。

译者按: 做一个有追求的工程师,代码不是随便写的!

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

小编推荐:Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和Java线上bug实时监控。真的是一个很好用的bug监控服务,众多大佬公司都在使用。

我保证这是一篇可以快速阅读并吸收的文章。在过去的几个月里,我检查的所有的pull request中,都犯了这4个的错误。我写这篇文章的另一个原因在于我自己也犯过这些错。我们来看看如何正确地使用它们!

1. 不要使用Array.indexOf,使用Array.includes

“如果你要在数组中查找元素,使用Array.indexOf!”。记得在我学习JavaScript课程时候,有这样一句话。这句话没错,确实可以这么使用!

根据MDN文档:“Array.indexOf会返回被查找元素第一个匹配的位置的下标。”因此,如果后面需要用到这个索引,Array.indexOf是一个很好的解法。

但是,我们要解决的问题是:查找数组中是否包含某个元素。这是一个Yes/No的问题,是一个返回布尔类型的真假问题。因此,我建议使用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

2. 不要使用Array.filter,使用Array.find

Array.filter是一个很有用的函数,它返回一个满足过滤条件的新数组。正如其名字表达的含义,它是用来做过滤的。

但是,如果我们知道我们要的结果只有一个元素的时候,我就不建议使用它了。比如,如果我们的回调函数定义用一个唯一的ID来过滤,那么结果必然唯一了。在这个情况下,Array.filter会返回只有一个元素的数组。因为既然能通过一个特定的ID来查找,我们已经确定只有一个元素了,那么使用数组就没有意义。

另外,我们再来聊聊性能问题。为了返回所有匹配的元素,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' }

3. 不要使用Array.find,使用Array.some

我承认我犯过很多次错误。后来,一个很要好的朋友让我去看看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

4. 不要使用Array.map和Array.filter组合,使用Array.reduce

Array.reduce有点难以理解!但是,如果我们每次在同时使用Array.filter和Array.map的时候,你是否觉察到需要点东西,对不?

我的意思是:我们对整个数组循环了2遍。第一次是过滤返回一个新的数组,第二次通过map又构造一个新的数组。我们使用了两个数组方法,每一个方法都有各自的回调函数,而且Array.filter返回的数组以后再也不会用到。

为了避免低效率,我建议使用Array.reduce。同样的结果,更优雅的代码!请看下面的例子:

'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'] }
// ]

备注

malgosiastp and David Piepgrass在评论中提到:在使用Array.find和Array.includes前请注意检查兼容性,因为最新的IE不支持。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

版权声明:
转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/09/06/make-better-use-of-arrays/

img_8668fd30f7bd630ef20b84c188e2989c.png
屏幕快照 2018-08-30 上午8.28.52.png
目录
相关文章
|
4天前
|
JavaScript 前端开发
js变量的作用域、作用域链、数据类型和转换应用案例
【4月更文挑战第27天】JavaScript 中变量有全局和局部作用域,全局变量在所有地方可访问,局部变量只限其定义的代码块。作用域链允许变量在当前块未定义时向上搜索父级作用域。语言支持多种数据类型,如字符串、数字、布尔值,可通过 `typeof` 检查类型。转换数据类型用 `parseInt` 或 `parseFloat`,将字符串转为数值。
10 1
|
7天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
18 3
|
20天前
|
存储 JavaScript 索引
JS中数组的相关方法介绍
JS中数组的相关方法介绍
|
20天前
|
JavaScript Java
JS有趣的灵魂 清空数组
JS有趣的灵魂 清空数组
|
2月前
|
JavaScript 计算机视觉
纯js实现人脸识别眨眨眼张张嘴案例——ccv.js
纯js实现人脸识别眨眨眼张张嘴案例——ccv.js
47 0
|
2月前
|
JavaScript 前端开发 Java
纯前端JS实现人脸识别眨眨眼张张嘴案例
纯前端JS实现人脸识别眨眨眼张张嘴案例
53 0
|
2月前
|
JavaScript 计算机视觉
纯js实现人脸识别眨眨眼张张嘴案例——alive_face.js
纯js实现人脸识别眨眨眼张张嘴案例——alive_face.js
23 0
|
1天前
|
JavaScript 前端开发 索引
JavaScript 数组的索引方法数组转换为字符串方法
JavaScript 数组的索引方法数组转换为字符串方法
|
4天前
|
JavaScript 前端开发
js的let、const、var的区别以及应用案例
【4月更文挑战第27天】ES6 中,`let` 和 `const` 是新增的变量声明关键字,与 `var` 存在显著差异。`let` 允许重新赋值,而 `const` 不可,且两者都具有块级作用域。`var` 拥有函数级作用域,并可在函数内任意位置访问。`let` 和 `const` 声明时必须初始化,而 `var` 不需。根据需求选择使用:局部作用域用 `let`/`const`,全局或函数范围用 `var`,不可变值用 `const`。
12 2
|
5天前
|
JavaScript 前端开发
js 操作数组的方法
js 操作数组的方法
15 4