目 录CONTENT

文章目录

JS 中的 reduce:一种函数式编程的艺术

萧瑟
2023-05-10 / 0 评论 / 12 点赞 / 296 阅读 / 5,856 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-07-03,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

reduce是JavaScript中一个非常强大的数组方法,它可以用来对数组中的元素进行累计操作,从而得到一个单一的值。reduce的基本用法是接受一个回调函数和一个初始值作为参数,然后遍历数组,将每个元素和累计值传递给回调函数,最后返回最终的累计值。reduce有很多超级实用的使用技巧,本文将介绍其中的10个,供大家参考。

1. 计算数组中元素的总和

这是reduce最常见的用法之一,可以用来计算数组中所有元素的总和。例如,如果我们有一个包含数字的数组,我们可以用reduce来求和:

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 15

这里,我们传递了一个箭头函数作为回调函数,它接受两个参数:acc表示累计值,cur表示当前元素。我们将它们相加并返回新的累计值。我们还传递了一个初始值0作为reduce的第二个参数,表示累计值的初始值。如果不传递初始值,reduce会默认使用数组的第一个元素作为初始值,但这可能会导致一些意想不到的结果,所以最好总是指定初始值。

2. 计算数组中元素的平均值

类似于求和,我们也可以用reduce来计算数组中元素的平均值。我们只需要在回调函数中将累计值除以数组的长度即可:

const numbers = [1, 2, 3, 4, 5];
const average = numbers.reduce((acc, cur) => acc + cur, 0) / numbers.length;
console.log(average); // 3

3. 计算数组中元素的最大值或最小值

除了求和和求平均,我们还可以用reduce来找出数组中元素的最大值或最小值。我们只需要在回调函数中使用Math.max或Math.min方法来比较累计值和当前元素,并返回较大或较小的那个:

const numbers = [1, 2, 3, 4, 5];
const max = numbers.reduce((acc, cur) => Math.max(acc, cur), -Infinity);
console.log(max); // 5
const min = numbers.reduce((acc, cur) => Math.min(acc, cur), Infinity);
console.log(min); // 1

这里,我们分别使用了-Infinity和Infinity作为初始值,表示最小和最大可能的数值。这样可以确保任何一个数组元素都能比较得出结果。

4. 将数组转换为对象

reduce不仅可以用来对数组进行数学运算,还可以用来将数组转换为其他类型的数据结构,例如对象。例如,如果我们有一个包含键值对的二维数组,我们可以用reduce来将它转换为一个对象:

const entries = [['name', 'Alice'], ['age', 18], ['gender', 'female']];
const obj = entries.reduce((acc, cur) => {
  acc[cur[0]] = cur[1];
  return acc;
}, {});
console.log(obj); // {name: "Alice", age: 18, gender: "female"}

这里,我们传递了一个空对象作为初始值,并在回调函数中将每个子数组的第一个元素作为对象的键,第二个元素作为对象的值,并返回新的对象。

5. 将对象转换为数组

反过来,我们也可以用reduce来将对象转换为数组,例如:

const obj = {
  name: 'Alice',
  age: 25,
  gender: 'female'
};

我们可以使用reduce函数来实现这个功能,代码如下:

const arr = Object.keys(obj).reduce((acc, key) => {
  acc.push([key, obj[key]]);
  return acc;
}, []);

console.log(arr); // [['name', 'Alice'], ['age', 25], ['gender', 'female']]

这样我们就得到了一个包含对象键值对的数组,可以方便地进行遍历或其他操作。

6、统计一个数组中每个元素出现的次数

如果我们想要统计一个数组中每个元素出现的次数,我们可以使用reduce方法来实现。例如:

let arr = ['a', 'b', 'c', 'a', 'b'];
let count = arr.reduce((obj, item) => {
  // 如果对象中已经有了这个键,就让它的值加一
  if (obj[item]) {
    obj[item]++;
  } else {
    // 如果对象中没有这个键,就初始化为一
    obj[item] = 1;
  }
  // 返回对象作为下一次的累计值
  return obj;
}, {}); // 初始值为空对象
console.log(count); // {a: 2, b: 2, c: 1}

7、按条件分组

假设我们有一个包含学生信息的数组,每个对象都有name和score属性,我们想要按照score是否大于等于60来分组,即及格和不及格。我们可以使用reduce这样做:

// 定义一个学生数组
const students = [
  {name: 'Alice', score: 75},
  {name: 'Bob', score: 59},
  {name: 'Charlie', score: 82},
  {name: 'David', score: 48},
  {name: 'Eve', score: 66}
];

// 使用reduce按条件分组
const groups = students.reduce((acc, cur) => {
  // 判断当前对象的score是否大于等于60
  const key = cur.score >= 60 ? 'pass' : 'fail';
  // 如果累积对象中还没有这个key,就创建一个空数组
  if (!acc[key]) {
    acc[key] = [];
  }
  // 将当前对象推入对应的数组
  acc[key].push(cur);
  // 返回累积对象
  return acc;
}, {}); // 初始值为一个空对象

// 打印结果
console.log(groups);
/*
{
  pass: [
    { name: 'Alice', score: 75 },
    { name: 'Charlie', score: 82 },
    { name: 'Eve', score: 66 }
  ],
  fail: [
    { name: 'Bob', score: 59 },
    { name: 'David', score: 48 }
  ]
}
*/

8、将多数组合并为一个对象

将多个数组合并为一个对象,例如,将一个包含用户信息的数组和一个包含用户订单的数组合并为一个包含用户信息和订单的对象。这样可以方便地对数据进行分析和处理。

要实现这个功能,我们可以使用reduce方法的第二个参数,即初始值。初始值可以是任何类型的值,包括一个空对象。然后,在reduce方法的回调函数中,我们可以根据数组元素的某个属性(例如用户ID)来判断是否已经存在对应的对象属性。如果不存在,就创建一个新的属性,并将数组元素赋值给它。如果存在,就将数组元素追加到已有的属性中。最后,返回累积的对象作为下一次迭代的初始值。

下面是一个示例代码:

// 用户信息数组
const users = [
{ id: 1, name: "Alice", age: 25 },
{ id: 2, name: "Bob", age: 30 },
{ id: 3, name: "Charlie", age: 35 },
];

// 用户订单数组
const orders = [
{ id: 1, userId: 2, product: "Book", price: 10 },
{ id: 2, userId: 1, product: "Pen", price: 5 },
{ id: 3, userId: 3, product: "Shirt", price: 20 },
{ id: 4, userId: 2, product: "Shoes", price: 15 },
];

// 使用reduce方法将两个数组合并为一个对象
const result = users.reduce((acc, user) => {
// 判断是否已经存在对应用户ID的属性
if (!acc[user.id]) {
  // 如果不存在,创建一个新的属性,并将用户信息赋值给它
  acc[user.id] = user;
  // 同时,创建一个空数组用来存储用户订单
  acc[user.id].orders = [];
}
// 遍历订单数组,找到属于当前用户的订单
for (let order of orders) {
  if (order.userId === user.id) {
    // 将订单追加到用户订单数组中
    acc[user.id].orders.push(order);
  }
}
// 返回累积的对象
return acc;
}, {}); // 初始值为空对象

// 打印结果
console.log(result);

/*
{
    "1": {
        "id": 1,
        "name": "Alice",
        "age": 25,
        "orders": [
            {
                "id": 2,
                "userId": 1,
                "product": "Pen",
                "price": 5
            }
        ]
    },
    "2": {
        "id": 2,
        "name": "Bob",
        "age": 30,
        "orders": [
            {
                "id": 1,
                "userId": 2,
                "product": "Book",
                "price": 10
            },
            {
                "id": 4,
                "userId": 2,
                "product": "Shoes",
                "price": 15
            }
        ]
    },
    "3": {
        "id": 3,
        "name": "Charlie",
        "age": 35,
        "orders": [
            {
                "id": 3,
                "userId": 3,
                "product": "Shirt",
                "price": 20
            }
        ]
    }
}
*/

9、将字符串转化为对象

我们经常会遇到在url上进行取值,当然这有很多种方法,我们用reduce方法来实现。

// 将URL参数转化为对象
let url = "https://www.example.com?name=Tom&age=20&gender=male";
let params = url.split("?")[1]; // 获取参数部分
let obj = params.split("&").reduce((acc, cur) => {
  let [key, value] = cur.split("="); // 分割键和值
  acc[key] = value; // 将键和值添加到对象中
  return acc;
}, {}); // 初始值为空对象
console.log(obj); // {name: "Tom", age: "20", gender: "male"}

10、检查字符串是不是回文字符

如果我们想要检查一个字符串是否是回文字符串,即正着读和反着读都一样,例如"racecar",我们可以使用reduce方法来实现。

首先,我们将字符串转换为数组,然后使用reduce方法从右到左遍历数组,将每个元素拼接到累积器上,得到一个反转后的字符串。然后,我们将反转后的字符串和原始字符串进行比较,如果相等,则说明是回文字符串,否则不是。

例如,给定字符串"racecar",我们可以这样写:

const isPalindrome = str => {
  // 将字符串转换为数组
  const arr = str.split('');
  // 使用reduce方法从右到左遍历数组,将每个元素拼接到累积器上
  const reversedStr = arr.reduce((accumulator, currentValue) => currentValue + accumulator, '');
  // 将反转后的字符串和原始字符串进行比较
  return reversedStr === str;
};

console.log(isPalindrome('racecar')); // true
console.log(isPalindrome('hello')); // false

当然还有其他写法

const fun = str => {
    let result = str.split('').reverse().toString().replaceAll(',','')
    return result === str
}
console.log(fun('abcd'))	// false
console.log(fun('abba'))	// true

weixin

12

评论区