当前位置: 首页 > news >正文

JavaScript数组方法reduce详解

JavaScript数组方法reduce详解

在这里插入图片描述

目录

  • JavaScript数组方法reduce详解
    • 一,前言
    • 二,核心语法
    • 三,案例
      • 1.求和
      • 2.找最大值
      • 3.数组转对象
      • 4.复合操作(同时实现 map + filter)
    • 四,常见错误
      • 1.空数组没有初始值
      • 2.没有返回累加值
      • 3.reduce 方法在遍历数组时,依赖于数组的长度和内容,如果在遍历过程中修改了数组(例如删除元素),会导致遍历逻辑混乱,结果不可预测。
    • 五,reduce 的 polyfill
    • 六,总结

一,前言

Reduce 是一种在函数式编程中常见的操作,它可以将一个序列(比如列表,数组)的所有元素通过某种规约逻辑合并成一个单一的数值。Reduce 的概念最早起源于函数式编程语言 Lisp,后来被广泛应用于其他语言中,如 Python ,javaScript。本文会用最易懂的方式帮你彻底掌握JavaScript数组reduce()方法。我们先从基础开始,逐步深入,最后通过实际案例巩固知识,最重要的是希望能够带给你一些思考。

二,核心语法

arr.reduce(callback(accumulator, currentValue, index, array), initialValue)
Accumulator(累计值)
CurrentValue(当前元素)
Index(当前索引)
Array(原数组)
initialValue(Accumulator的初始值)

三,案例

1.求和

const nums = [1, 2, 3];
const sum = nums.reduce((acc, num) => acc + num, 0);

代码分析:
此求和案例分别用了参数acc和num代表Accumulator和CurrentValue,并且将Accumulator的初始值赋为0。
运算步骤:
1,初始值为0,acc为0加第一次的当前值1 返回1
2,acc为1加第二次循环的当前值2,返回3
3,acc为3加第三次循环的当前值3,返回6

2.找最大值

const max = [4, 2, 7, 5].reduce((a, b) => Math.max(a, b), -Infinity);

代码分析:
此求最大值案例分别用了参数a和b代表Accumulator和CurrentValue,并且将Accumulator的初始值赋为-Infinity(负无穷大)。
运算步骤:
1,首先是负无穷和第一次的当前值4比较,返回4
2,a为4,和第二次的当前值2比较,返回4
3,a为4,和第三次当前值7比较,返回7
4,a为7,和第四次当前值5比较,返回7
说明:
-Infinity 是 JavaScript 中的一个特殊值,表示负无穷大。它不是变量,而是一个全局属性,属于 JavaScript 的 基本数据类型 之一。
这里也可以更换 -Infinity为100,那么max的返回值就是100。

3.数组转对象

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

const userMap = users.reduce((obj, user) => {
  obj[user.id] = user;
  return obj; 
}, {});

返回结果:

{
    "1": {
        "id": 1,
        "name": "Alice"
    },
    "2": {
        "id": 2,
        "name": "Bob"
    }
}

说明:
数组转对象案例这里主要是想体现一下设置初始值的重要性
这里如果不设置其默认初始值可以先看一下返回结果的区别

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

const userMap = users.reduce((obj, user) => {
  obj[user.id] = user;
  return obj; 
});

返回值:

{
    "2": {
        "id": 2,
        "name": "Bob"
    },
    "id": 1,
    "name": "Alice"
}

代码分析:
要想弄明白为什么没有设置空的初始值显示结果是这样,我们首先回到案例1求和的代码,
之前我们分析结论是基于有返回值的情况下得出的

1,初始值为0,acc为0加第一次的当前值1 返回1
2,acc为1加第二次循环的当前值2,返回3
3,acc为3加第三次循环的当前值3,返回6

那么如果对于求和案例不设置初始值又该如何分析呢?
对于没有设置初始值的reduce分析:第一次迭代时,acc 是数组的第一个元素,num 是数组的第二个元素。得到这个结论我们返回来分析代码:

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

const userMap = users.reduce((obj, user) => {
  obj[user.id] = user;
  return obj; 
});

因为没有返回值,第一次obj是 { id: 1, name: ‘Alice’ },user是 { id: 2, name: ‘Bob’ }
执行 obj[user.id] = user 后,obj 变为 { id: 1, name: ‘Alice’, 2: { id: 2, name: ‘Bob’ } }。

注意:
JavaScript的reduce函数有没有设置初始值,直接影响第一次执行的Accumulator和CurrentValue

4.复合操作(同时实现 map + filter)

const numbers = [1, 2, 3, 4];
const doubledEvens = numbers.reduce((arr, num) => {
  if (num % 2 === 0) {
    arr.push(num * 2);
  }
  return arr;
}, []);
// 结果:[4, 8](先过滤偶数,再翻倍)

代码分析:
此求和案例分别用了参数arr和num代表Accumulator和CurrentValue,并且将Accumulator的初始值赋为[]。此例子中必须要设置Accumulator的初始值为[ ],否则,Accumulator的初始值是1,不是数组没有push方法就会报错。

四,常见错误

1.空数组没有初始值

[].reduce((a, b) => a + b); // 报错!

2.没有返回累加值

// 错误示例
[1,2,3].reduce((acc, num) => {
  acc + num; // 没有 return!
});
// 正确:必须显式返回 acc

3.reduce 方法在遍历数组时,依赖于数组的长度和内容,如果在遍历过程中修改了数组(例如删除元素),会导致遍历逻辑混乱,结果不可预测。

五,reduce 的 polyfill

Polyfill 是指在不支持某个新特性的旧浏览器中,用 JavaScript 实现该特性的代码。换句话说,它是一个“补丁”,用来填补浏览器原生功能的缺失。
用白话说就是自己实现reduce,通过自己实现 reduce,可以更深入地理解它的工作原理。

Array.prototype.myReduce = function (callback, initialValue) {
  // 1. 检查 this 是否为 null 或 undefined
  if (this == null) {
    throw new TypeError('Array.prototype.myReduce called on null or undefined');
  }

  // 2. 检查 callback 是否是函数
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }

  const array = Object(this); // 将 this 转换为对象
  const length = array.length >>> 0; // 确保 length 是正整数

  let accumulator;
  let startIndex = 0;

  // 3. 处理初始值
  if (arguments.length >= 2) {
    accumulator = initialValue; // 如果有初始值,直接使用
  } else {
    // 如果没有初始值,取数组的第一个元素作为初始值
    if (length === 0) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    accumulator = array[0];
    startIndex = 1; // 从第二个元素开始遍历
  }

  // 4. 遍历数组
  for (let i = startIndex; i < length; i++) {
    if (i in array) {
      // 调用回调函数,更新 accumulator
      accumulator = callback(accumulator, array[i], i, array);
    }
  }

  // 5. 返回最终结果
  return accumulator;
};

使用示例:

const nums = [1, 2, 3, 4];

// 求和
const sum = nums.myReduce((acc, num) => acc + num, 0);
console.log(sum); // 10

// 找最大值
const max = nums.myReduce((acc, num) => Math.max(acc, num), -Infinity);
console.log(max); // 4

// 数组转字符串
const str = nums.myReduce((acc, num) => acc + num.toString(), '');
console.log(str); // '1234'

六,总结

reduce的参数看起来多,但是认真体会上面的案例不难理解,难点是如何记住

Accumulator(累计值)
CurrentValue(当前元素)
Index(当前索引)
Array(原数组)

参数顺序口诀:“All Cows In Australia”(ACIA)

相关文章:

  • 1.1 go环境搭建及基本使用
  • PHP约课健身管理系统小程序源码
  • SpringSecurity基于注解实现方法级别授权:@PreAuthorize、@PostAuthorize、@Secured
  • python-leetcode-环形链表 II
  • Web刷题之PolarDN(简单)
  • Uniapp 开发中遇到的坑与注意事项:全面指南
  • Linux基础指令
  • 达梦数据库-寒假实训
  • 深入浅出:基于SpringBoot和JWT的后端鉴权系统设计与实现
  • vue2.x 中父组件通过props向子组件传递数据详细解读
  • Linux 系统中的软链接与硬链接
  • (java/Spring boot)使用火山引擎官方推荐方法向大模型发送请求
  • Ubuntu DeepSeek磁盘空间不够解决办法
  • SQL写法技巧
  • Elasticsearch:探索 CLIP 替代方案
  • Python Django系列—入门实例(二)
  • Spring扩展点之Mybatis整合模拟
  • 深入理解 JSP 与 Servlet:原理、交互及实战应用
  • Java计算机毕业设计基于SSM宠物美容信息管理系统数据库源代码+LW文档+开题报告+答辩稿+部署教程+代码讲解
  • HTML中,title和h1标签的区别是什么?
  • 百度广州分公司总经理/百度seo多久能优化关键词
  • 免费客服系统下载/西安优化排名推广
  • 室内设计培训班有用吗/seo的中文意思
  • 网站模板html/郑州seo优化顾问
  • 许昌市住房和城乡建设局门户网站/百度新闻排行榜
  • 政府网站建设多少钱/广东网络seo推广公司