JavaScript数组方法reduce使用详解
作者:sleep_i_like
一,前言
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的资料请关注脚本之家其它相关文章!