Henry Henry
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)

Henry

小学生中的前端大佬
  • JavaScript
  • TypeScript
  • Vue
  • ElementUI
  • React
  • HTML
  • CSS
  • 技术文档
  • GitHub 技巧
  • Nodejs
  • Chrome
  • VSCode
  • Other
  • Mac
  • Windows
  • Linux
  • Vim
  • VSCode
  • Chrome
  • iTerm
  • Mac
  • Obsidian
  • lazygit
  • Vim 技巧
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • Vue 资源
GitHub (opens new window)
  • JavaScript

    • js 编码指南
    • 日期使用斜杠 点 中划线分隔的不同
    • forEach 会改变原数组值吗
    • 前端表单验证常用的正则表达式 - reg
    • JS 如何取得 URL 里的参数
    • JavaScript 数组去重
    • JavaScript 循环中断研究与总结-关键字篇
    • JavaScript 循环中断研究与总结-用法篇
    • js 中的 Error
    • 跳出 forEach
    • Location 对象
    • Date 方法预览
    • Reg 正则中的问题
    • JavaScript toFixed() 方法
    • query 和 params 的使用区别
    • axios post 请求中下载文件流
    • 实用的 js 技巧
    • JS 之数组的几个不 low 操作
    • 深入浅出深拷贝与浅拷贝
    • 如何实现一个深拷贝
    • 使用 iframe 中的一些问题
    • 在 js 中更好地使用数组
      • 使用 Array.includes 替代 Array.indexOf
      • 使用 Array.find 替代 Array.filter
      • 使用 Array.some 替代 Array.find
      • 使用 Array.reduce 替代 Array.filter 与 Array.map 的组合
      • 这就是本文的全部内容!
    • echarts 在坐标轴两侧各增加一格坐标
    • 从头认识js的事件循环模型
    • moment 根据周截至日算出指定月有几周及开始结束日期
    • 正则 reg 中 /number 的用法
    • 正则 reg 中 match 和 exec 异同
  • TypeScript

  • Vue

  • ElementUI

  • React

  • AntD

  • 前端
  • JavaScript
Henry
2018-07-29
目录

在 js 中更好地使用数组

关于数组方法的使用上, 我们经常会犯一些错误, 因此有了这篇文章. 让我们一起学习, 以确保以后能正确地使用数组方法!

# 使用 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
1
2
3
4
5
6
7
8
9
10
11
12
13

# 使用 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' }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 使用 Array.some 替代 Array.find

我承认我经常犯这个错误. 之后, 一位朋友建议我去查看 MDN 文档 (opens new window) 以寻找更好的方法. 事实上(这错误)与上面 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

补充一下 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'] }
// ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 这就是本文的全部内容!

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

编辑 (opens new window)
#Js
上次更新: 5/27/2023, 1:02:05 PM
使用 iframe 中的一些问题
echarts 在坐标轴两侧各增加一格坐标

← 使用 iframe 中的一些问题 echarts 在坐标轴两侧各增加一格坐标→

最近更新
01
version 1.15
07-01
02
version 1.14
06-27
03
version 1.13
06-27
更多文章>
Theme by Vdoing | Copyright © 2017-2023 HenryTSZ | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式