javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript方法reduce

JavaScript数组方法reduce使用详解

作者:sleep_i_like

本文详细介绍了JavaScript数组reduce()方法的使用,包括核心语法、常见案例以及常见错误,通过实际案例和代码分析,帮助读者彻底掌握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

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)

以上就是JavaScript数组方法reduce详解的详细内容,更多关于JavaScript方法reduce的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文