学习如何使用最强大的 JavaScript函数

今天你将学习如何使用最强大的 JavaScript函数。


数组归约


"Array.reduce最强大的 JavaScript Function. 时期。 "


reduce有什么作用?为何如此强大?

这是reduce的技术定义......

Array.prototype.reduce()


reduce() 方法对数组的每个元素执行(您提供的)reducer 函数,从而产生单个输出值。

如果你问我的话,这没什么帮助,所以让我们边做边学


1. 求所有数字的总和(使用reduce)


typescript 复制代码
[3, 2.1, 5, 8].reduce((total, number) => total + number, 0)// loop 1: 0 + 3// loop 2: 3 + 2.1// loop 3: 5.1 + 5// loop 4: 10.1 + 8// returns 18.1

2. 求所有相乘数的总和


typescript 复制代码
[3, 2.1, 5, 8].reduce((total, number) => total * number, 1)

如图所示,将数组中的所有数字相加或相乘非常容易。但是, -我说过,reduce 是所有 JS 中最强大的函数。

假设我们有341060。假设我们想要获得一些值。

或者,更具体地说,我们想要filter这些值,并且只返回小于 10 的值。

通常,我们可以简单地使用该filter函数,只返回小于 10 的数字。


3. 使用reduce进行Array.Filter


ini 复制代码
[3, 4, 10, 60].filter(number => number < 10)

好吧,使用reduce------我们可以做同样的事情。

typescript 复制代码
[3, 4, 10, 60].reduce((list, number) => 
   number < 10
      ? [...list, number]
      : list, [])

拉拉,我们用 reduce替换了过滤器 - 很酷,但说实话。这仍然不能证明reduce它是所有 JavaScript 中最强大的功能


如果我告诉你,我们可以继续沿着这条路走,并使用 reduce 替换 JavaScript 中的几乎所有数组函数,会怎么样?



4. 重新创建Array.some使用Array.reduce


sql 复制代码
[3, 4, 10, 50].some(number => number < 50)// returns true (We have some numbers in the array are less than 50)

使用reduce,我们只需将初始值设置为false。如果条件已经为真,那么我们返回该条件。如果条件尚不成立,那么我们检查当前数字是否满足我们的条件。

typescript 复制代码
[3, 4, 10, 50].reduce((condition, number) => 
   condition === true  
       ? condition
       : number < 50, false)

请注意,这次我们以 bool (false) 作为初始值,而不是使用数字或数组。


我们现在已经求和、相乘、过滤并重新创建了一些(也称为使用reduce 有条件地检查数组上的某些内容)。

我们还可以继续Array.every使用 using 替换该函数,但由于这与替换usingArray.reduce类似,因此我们也可以轻松地做到这一点。Array.some``Array.reduce


5.Array.join4.使用 怎么样Array.reduce


替换Array.joinArray.reduce

bash 复制代码
['truck', 'car', 'people'].join('-')// "truck-car-people"

使用Array.reduce我们可以编写以下代码

javascript 复制代码
['truck', 'car', 'people'].reduce((text, word) => `${text}-${word}`, '')// "-truck-car-people"

请注意,输出的前面有一个破折号。

作为函数的第一个参数接受的回调函数Array.reduce接受更多参数。我们可以使用第三个接受的参数来跟踪我们index的reduce函数

javascript 复制代码
['truck', 'car', 'people'].reduce((text, word, index) => 
    index === 0
       ? word 
       : `${text}-${word}`, '')// "truck-car-people"

设置第三个参数后,这个reduce函数现在将按照原始Array.join函数的方式运行


至此,我们已经使用reduce进行替换了。

  • Array.map
  • 数组过滤器
  • 数组.every,数组.some
  • 数组连接

6. 使用Reduce进行Array.concat


那么连接呢?在哪里可以将"1"、"2"和"3"的数组与另一个数组连接起来?

css 复制代码
[1, 2, 3].concat(['hey', 'world', 'mars'])// [1, 2, 3, 'hey', 'world', 'mars']

您将如何连接或组合数组reduce?

css 复制代码
[[1,2,3], ['hey', 'world', 'mars']].reduce(
   (list, array) => [...list, ...array],[])// [1, 2, 3, 'hey, 'world', 'mars']

使用组合数组的好处Array.reduce是我们可以"连接"任意数量的数组。

简单地说,通过传入更多数组,我们将使用reduce 自动组合(也称为连接)它们。

这样,我们就复制了Array.concat使用Array.reduce


让我们再看几个例子。

首先,让我们创建一些人。

bash 复制代码
let sarah = { name: 'sarah', email: 'sarah@gmail.com', id: 1 }let tim = { name: 'tim', email: 'tim@gmail.com', id: 2 }let len = { name: 'len', email: 'len@gmail.com', id: 3 }

7. 使用按姓名对人员进行分组Array.reduce


当我们按名字对人进行分组时我们想要的示例

python 复制代码
people.len// Gets Len// { name: 'len', email: 'len@gmail.com', id: 3 }people.sarah// Gets sarah// { name: 'sarah', email: 'sarah@gmail.com', id: 1}

使用reduce 按姓名对人员进行分组

  • 将reduce函数的初始值设置为一个对象

  • 构建一个对象,其中

    • 关键是人的名字([person.name])
    • 该值为 person 对象([person.name]: person)

示例(这不起作用)

less 复制代码
let people = [sarah, tim, len].reduce((people, person) => {
   [person.name]: person,
   ...people}, {}) 

在上面的例子中我们会得到一个错误

未捕获的语法错误:意外的标记":"

每当我们使用简写函数返回一个对象时,我们需要将其括在括号中

  • 将返回对象的方括号括在圆括号中以修复错误
css 复制代码
let people = [sarah, tim, len].reduce((people, person) => ({
   [person.name]: person,
   ...people}), {}) 

啦啦,我们现在有一个人员对象,其中人员按姓名分组

如果我们去,people.len我们会得到 len

python 复制代码
people.len // { name: 'len', email: 'len@gmail.com', id: 3 }

如果我们去的话people.sarah我们会得到莎拉

bash 复制代码
people.sarah // { name: 'sarah', email: 'sarah@gmail.com', id: 1 }

如果我们去的话people.tim我们会得到蒂姆

bash 复制代码
people.tim // { name: 'tim', email: 'tim@gmail.com', id: 2 }

如果我们想要我们所有的people

css 复制代码
// people {
   sarah: { name: 'sarah', email: 'sarah@gmail.com', id: 1 },
   tim: { name: 'tim', email: 'tim@gmail.com', id: 2 },
   len: { name: 'len', email: 'len@gmail.com', id: 3 },}

8. 使用Reduce 按给定键提取值数组


更重要的是,如果我们只想获取人员的姓名怎么办?

css 复制代码
let names = [sarah, tim, len].reduce((names, person) => [   ...names,   person.name], [])// ['sarah', 'tim', 'len']

如果我们只想获取人们的电子邮件怎么办?

css 复制代码
let emails = [sarah, tim, len].reduce((emails, person) => [   ...emails,   person.email], [])// ['sarah@gmail.com', 'tim@gmail.com', 'len@gmail.com']

9. 使用Reduce 展平多层嵌套数组


更重要的是,如果我们有一个嵌套数组的数组怎么办?

ini 复制代码
let list_of_arrays = [
    ['sub_one', 'sub_two', 'sub_three'],
    [
       ['nested_sub_one', 'nested_sub_two'], 
       ['nested_sub_three', 'nested_sub_four']
    ],
    'one',
    'two',
    'three']

让我们使用数组列表,当然还可以使用reduce

javascript 复制代码
list_of_arrays.reduce((flattened, item) => {
   if (Array.isArray(item) === false) {
      return [...flattened, item]
   }
   if (Array.isArray(item) && Array.isArray(item[0])) {
      return [
         ...flattened,
         ....item.reduced((flatten, nested_list) => [...flatten, ...nested_list, [])
       ]
      ]
   }
   return [...flattened, ...item]}, [])

啦啦,我们已经扁平化了多层嵌套数组的列表。

输出

css 复制代码
["sub_one", "sub_two", "sub_three", "nested_sub_one", "nested_sub_two", "nested_sub_three", "nested_sub_four", "one", "two", "three"]

笔记:

我们只处理最多 3 层深度的嵌套子数组,但是您当然可以在该函数上花费更多时间,并使用递归来非常简单地使用 reduce 来展平无限嵌套层深的数组。


更强大的Reduce用例


好吧,现在让我们深入研究一些更强大但不常用的用例Array.reduce


10. 在字符串上应用格式化程序


我将从一系列字符串开始。

ini 复制代码
let strings = ['cool-link', 'hello world of javascript', 'goodbye, its been swell']

接下来让我们创建一个formatters. 通常,我将这些称为过滤器 - 但它们并不是真正的过滤器。他们只是格式化字符串。

这些格式化程序实际上是回调函数。

首先,我们将创建一个破折号到空格格式化程序(用空格替换破折号)。将使用正则表达式来实现此格式化程序。

javascript 复制代码
let dashesToSpaces = str => str.replace(/-/g, ' ')

接下来,我们将创建一个大写字符串格式化程序。

ini 复制代码
let capitalize = str => `${str[0].toUpperCase()}${str.slice(1)}`

然后,我们将创建一个字符串限制器格式化程序。

如果字符串大于给定长度,则用三个点替换该长度限制之后的字符。

python 复制代码
let limiter = str => str.length > 10 ? `${str.slice(0, 10)}...` : str 

formatters最后,我们将使用所有字符串格式化程序创建一个数组。

ini 复制代码
let formatters = [dashesToSpaces, capitalize, limiter]

请记住,我们有字符串数组。

ini 复制代码
let strings = ['cool-link', 'hello world of javascript', 'goodbye, its been swell']

我们的目标:

我们的目标是将格式化程序数组中的每个格式化程序应用到字符串数组中的每个字符串上。

使用reduce,我们可以简单地这样做!

typescript 复制代码
strings.reduce((list, str) => [
      formatters.reduce((string, format) => format(string), str),
      ...list
   ],[])

就像这样,我们使用reduce 在字符串数组上应用格式化程序数组。

原始字符串数组

css 复制代码
['cool-link', 'hello world of javascript', 'goodbye, its been swell']

输出(使用reduce应用字符串格式化程序后)

css 复制代码
["Goodbye, i...", "Hello worl...", "Cool link"]

11.按房间对学生进行分组(使用reduce)


首先我们创建一些学生

ini 复制代码
let students = [
   { name: 'Sally', room: 'A' },
   { name: 'tim', room: 'A' },
   { name: 'nick', room: 'B' },
   { name: 'rick', room: 'C' },
   { name: 'sarah', room: 'B' },
   { name: 'pam', room: 'C' }]

我们想按学生的房间对他们进行分组

所以我们要做的就是使用students.reduce.

javascript 复制代码
students.reduce((class_rooms, student) => ({}), {})

请注意,我们在再次隐式返回的对象周围使用了括号。当我们使用简写函数返回一个对象时,我们必须使用({})语法 - 如果我们尝试直接返回一个对象而不进行包装,()我们将收到错误。

接下来,我们要使用学生房间作为钥匙:

ini 复制代码
students.reduce((rooms, student) => ({
   ...rooms,
   [student.room]: rooms[student.room]
        ? [...rooms[student.room], student]
        : [student]}), {})

现在,我们的学生按房间/班级分组。

css 复制代码
{
   A: [{ name: 'sally', room: 'A' }, { name: 'tim', room: 'A' }],
   B: [{ name: 'nick', room: 'B' }, { name: 'sarah', room: 'B'}],
   C: [{ name: 'rick', room: 'C' }, { name: 'pam', room: 'C' }],}

我们已经成功地按学生的房间对学生进行了分组 - 这就是我们按归约进行分组的方式。


这就是我对reduce 的了解。我想最大的收获是,reduce 是一种超级方法 - 确实是如此!

使用reduce 可以做任何其他数组方法可以做的事情。

Array.filter.map.filter.forEach您可以使用单个reduce 函数来完成相同的目标。

如果您需要按键对一大堆对象进行分组,请使用reduce。

如果您需要提取与给定键相关的值?使用reduce。

如果您需要应用多个过滤器,但又不想通过多次迭代同一数组来提高时间复杂度 - 请使用reduce。

如果您想展平嵌套数组的数组,其中每个嵌套数组可能有更多嵌套数组,而每个嵌套数组也可能没有任何嵌套数组?使用reduce。

如果你需要对一些数字进行求和、乘以一些数字、减去总和或进行任何类型的算术------reduce 会再次起作用。

如果需要组合一些数组怎么办?使用reduce。

如果您需要组合一些对象怎么办?使用reduce。

如果您想拥有一种方法,您知道它可以完成所有工作,并且让您感觉作为软件工程师更加强大和高效,该怎么办?使用reduce!

在我看来,forEach 是 JavaScript 生态系统中最被高估的方法,reduce 是JS 生态系统中最被低估的方法。


作为最后一个例子,让我们以这个最后的例子来说明reduce 有多牛。

scss 复制代码
[{ name: 'Clean Code Studio' }, { belief: 'Simplify!' }, { should_follow: 'Si, senor!' }].reduce((last_example, partial) => ({ 
   ...last_example, ...partial }), {})

这会返回什么?它合并所有对象。

css 复制代码
{
   name: 'Clean Code Studio',
   belief: 'Simplify',
   should_follow: 'Si, senor!'}

使用reduce,你可以过滤,你可以应用,你可以应用回调列表,你可以展平,合并,组合......

强烈建议您熟悉、胜任并且总体上熟悉如何使用reduce。

同样,使用reduce你有两个参数。

  • 累加器 - 回调函数
  • 初始值 - 在累加器回调函数第一次迭代期间使用
scss 复制代码
[].reduce(accumulatorCallbackFunction, initialValue)

Accumulator回调函数有四个参数

  • accumulator - 每次迭代后从回调函数返回的值
  • item - 数组中的元素
  • index - 传递到累加器回调中的当前元素的索引
  • source - 正在调用原始数组reduce
scss 复制代码
let initial = []let callback = (accumulator, item, index, source) => {}[].reduce(callback, initial)

最后,最后一个额外的提示 - 如果您想在迭代完所有项目之前突破归约,该怎么办?

scss 复制代码
[].reduce((build, item, index, source) => source.slice(index), 0)

通过在给定索引处对源数组进行切片,您将摆脱reduce函数循环 - 因此,如果您有一个大数据集,一旦满足条件,您就可以停止使用计算资源。


最后,我强烈建议练习reduce。我发现它绝对是最有用的 JavaScript 函数。很多时候,reduce 已经成为以简洁、中肯的方式解决复杂编码挑战的解决方案。

s.juejin.cn/ds/ieyRoEGe...

相关推荐
Мартин.3 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。4 小时前
案例-表白墙简单实现
前端·javascript·css
数云界4 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd4 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常4 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer4 小时前
Vite:为什么选 Vite
前端
笑非不退4 小时前
前端框架对比和选择
前端框架
小御姐@stella4 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing4 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing4 小时前
WebGL在低配置电脑的应用
javascript