大家好,欢迎来到IT知识分享网。
reduce()函数是 ECMAScript 6 (ES6) 中数组的一个迭代方法,它接收一个回调函数作为累加器(accumulator),对该数组的所有元素(从左到右)执行操作,最后将计算结果累积为单一输出值。
reduce 函数是 JavaScript 中的一个功能强大的高阶函数,它算是 JS 数组方法里面较为复杂的一个函数了。reduce 的灵活性在于它能够遍历数组的所有元素,根据提供的函数累积一个最终的返回值。reduce()方法可以应用的场景特别多,循环遍历能做的,reduce都可以做,比如数组求和、数组求积、统计数组中元素出现的次数、数组去重等等。
一、reduce的用法
reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被作为初始值 initialValue,迭代器将从第二个元素开始执行(索引为 1 而不是 0)。
注意: reduce() 对于空数组是不会执行回调函数的。
语法如下:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue
简洁语法:
reduce(callbackFn, initialValue)
function(total,currentValue, index,arr):回调函数,必需。
- total:上一次回调函数的返回值,第一次调用回调函数时,如果指定的初始值 initialValue,那么该参数值就是 initialValue,否则就是数组元素的第一个。
- currentValue:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,那么当前处理的元素就是数组的第一个元素,否则的话就是第二个元素。
- currentIndex:数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。
- array:用于遍历的数组。
initialValue:可选。传递给函数的初始值。也就是第一次调用回调函数时参数total,是否指定初始值将会影响其它几个参数的值。
reduce 方法的返回值就是遍历所有数组执行回调函数后的返回值。
二、reduce的使用场景
2.1 数组求和
日常开发基本使用中,最简单其实就是数组求和的场景了。代码如下:
const arr = [1, 2, 3, 4, 5, 6, 7, 8]; const result = arr.reduce((total, currentValue) => { return total + currentValue; }, 0); console.log(result); // 36
按指定属性求和:
const arr = [ { name: '小明', score: 98 }, { name: '小花', score: 96 }, { name: '小强', score: 90 }, ]; const result = arr.reduce((total, currentValue) => { return total + currentValue.score }, 0); console.log(result); // 284
按照条件求和:
const arr = [ { name: '张三', score: 93 }, { name: '李四', score: 76 }, { name: '王五', score: 80 }, { name: '赵六', score: 65 }, ]; const result = arr.reduce((total, currentValue) => { return currentValue.score >= 80 ? total + currentValue.score : total; }, 0); console.log(result); // 173
2.2 计算数组每个数据出现的次数
这种场景通常出现在算法题当中,借助 reduce 就可以简单实现它。其主要思路是通过键值对的形式巧妙的将出现的次数存储下来。
代码如下:
const arr = ['Allice', 'Bob', 'Tiff', 'Bruce', 'Bob', 'Jack', 'Allice', 'Bob']; const result = arr.reduce((total, currentValue) => { total[currentValue] = (total[currentValue] || 0) + 1; return total; }, {}); console.log(result); // {Allice: 2, Bob: 3, Tiff: 1, Bruce: 1, Jack: 1}
变形:
同样的道理,也可以统计字符串中每个字符的出现次数,只需把字符串使用split方法分割成数组即可。
const str = 'Hello World'; const result = str.split('').reduce((total, currentValue) => { total[currentValue] = (total[currentValue] || 0) + 1; return total; }, {}); console.log(result); // {H: 1, e: 1, l: 3, o: 2, " ": 1, d: 1, r: 1, W: 1
2.3 数组去重
想不到吧!reduce还能实现数组去重?是的!
过程如下:
- 初始化一个空数组;
- 将需要去重处理的数组中的第1项在初始化数组中查找,如果找不到(空数组中肯定找不到),就将该项添加到初始化数组中;
- 将需要去重处理的数组中的第2项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中;
- ……;
- 将需要去重处理的数组中的第n项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中;
- 将这个初始化数组返回。
代码如下:
const arr = [1, 2, 2, 3, 3, 4, 4, 5, 6]; const result = arr.reduce((total, currentValue) => { if(!total.includes(currentValue)) { total.push(currentValue) } return total; }, []); console.log(result); // [1, 2, 3, 4, 5, 6]
2.4 数组扁平化
将初始值设置为了空数组,然后利用 concat 将数组中的每一项与初始值拼接,得到一个新的数组。
const arr = [['a', 'b'], ['c', 'd'], ['e', 'f']]; const result = arr.reduce((total, currentValue) => { return total.concat(currentValue); }, []); console.log(result); // ['a', 'b', 'c', 'd', 'e', 'f']
2.5 将二维数组转为对象
又没想到吧!将二维数组转化为对象,其过程为将初始值设置为了空对象,currentValue可以看做为[key, value],然后total[key] = value把键值放入total对象中。
const arr = [['name', '张三'], ['age', '30'], ['sex', '男']]; const result = arr.reduce((total, [key, value]) => { total[key] = value return total; }, {}); console.log(result); // {name: '张三', age: '30', sex: '男'}
2.6 提取数组中的特定值生产新数组
const arr = [{id: 1, name: 'Tom'}, { id: 2, name: 'Jack' }, { id: 3, name: 'Anna' }] const result = arr.reduce((total, currentValue) => { return [...total, currentValue.name] }, []); console.log(result); // ['Tom', 'Jack', 'Anna']
2.7 合并数组对象
const arr = [{name: '张三'}, { age: 30 }, { sex: '男' }]; const result = arr.reduce((total, currentValue) => { return { ...total, ...currentValue } }, {}); console.log(result); // {name: '张三', age: 30, sex: '男'}
2.8 解析url参数
const url = 'https://www.csdn.com/index.html?name=lvbin&id=666666&latitude=31.101109&longitude=121.51367';
const params = url.split('?')[1];
const result = params.split('&').reduce((total, currentValue) => {
const [key, value] = currentValue.split('=');
total[key] = value;
return total;
}, {});
console.log(result);
// {name: 'lvbin', id: '666666', latitude: '31.101109', longitude: '121.51367'}
2.9 反序列化参数
const stringifyData = (data = {}) => {
return Object.entries(data).reduce((total, currentValue) => {
return `${total}${currentValue[0]}=${encodeURIComponent(currentValue[1])}&`
}, Object.keys(data).length ? "?" : "")
.replace(/&$/, "");
};
const params = stringifyData({
name: "Jack",
id: '123456',
age: 18
});
const url = `https://www.test.com/index.html${params}`;
console.log(url);
// https://www.test.com/index.html?name=Jack&id=123456&age=18
2.10 求最大值、最小值
计算数组中的最大值或最小值,可以使用原生api Math.max()和Math.min(),当然我们也可以使用reduce来实现。
const array = [1, 10, 6, 8, 3, 9]; const max = array.reduce((max, num) => (max > num ? max : num)); console.log(max); // 10 const min = array.reduce((min, num) => (min < num ? min : num)); console.log(min); // 1
2.11 根据指定项分组
const arr = [ { name: '小明', score: 96 }, { name: '小华', score: 88 }, { name: '小红', score: 92 }, { name: '小刚', score: 100 }, { name: '小李', score: 96 }, { name: '小美', score: 90 }, { name: '小芳', score: 100 }, ] const result = arr.reduce((total, currentValue) => { const { score } = currentValue; if(!total[score]) total[score] = []; total[score].push(currentValue) return total; }, {}) console.log(result) //{"88":[{"name":"小华","score":88}],"90":[{"name":"小美","score":90}],"92":[{"name":"小红","score":92}],"96":[{"name":"小明","score":96},{"name":"小李","score":96}],"100":[{"name":"小刚","score":100},{"name":"小芳","score":100}]}
更复杂场景,多条件数据分类。
假设有一个包含人员信息的数组,每个人员对象有 age 和 gender 属性。现在我们想要根据人员的年龄和性别进行多条件分类。
const arr = [ { name: 'Alice', age: 25, gender: 'female' }, { name: 'Bob', age: 30, gender: 'male' }, { name: 'Charlie', age: 25, gender: 'male' }, { name: 'Dave', age: 35, gender: 'male' }, { name: 'Eve', age: 25, gender: 'female' }, ]; const result = arr.reduce((accumulator, person) => { const { age, gender } = person; if (!accumulator[age]) { accumulator[age] = {}; } if (!accumulator[age][gender]) { accumulator[age][gender] = []; } accumulator[age][gender].push(person); return accumulator; }, {}); console.log(result); //{"25":{"female":[{"name":"Alice","age":25,"gender":"female"},{"name":"Eve","age":25,"gender":"female"}],"male":[{"name":"Charlie","age":25,"gender":"male"}]},"30":{"male":[{"name":"Bob","age":30,"gender":"male"}]},"35":{"male":[{"name":"Dave","age":35,"gender":"male"}]}}
2.12 管道函数
当结合其他高阶用法时,reduce 可以应用于非常复杂的场景。其中一个非常复杂的场景是实现函数组合或管道。管道(Pipe)是指输入一个值,依次经过管道(有序的函数运算)后输出这个值,也是函数编程的核心思想。
函数组合是一种将多个函数合并成一个新函数的技术,其中每个函数的输出都是下一个函数的输入。我们可以使用 reduce 和函数组合技术来实现函数管道,将一系列函数应用于数据并依次传递结果。
function add10(num) { return num + 10; }; function multipl2(num) { return num * 2; }; function divide3(num) { return num / 3; }; const compose = (fns) => (initialValue) => fns.reduce((previous, current) => current(previous), initialValue); const calculate1 = compose([add10, divide3]); const calculate2 = compose([divide3, add10, multipl2]); // 先加10,在除以3 console.log(calculate1(20)); //10 // 先加10,在除以3,最后乘以2 console.log(calculate2(9)); //26
三、总结
reduce 是数组的归并方法,与forEach、map、filter等迭代方法一样都会对数组每一项进行遍历,但是reduce可同时将前面数组项遍历产生的结果与当前遍历项进行运算,这一点是其它迭代方法无法企及的。
reduce除了以上介绍的使用场景外,还有很多其它使用场景,有兴趣的朋友可以研究一下。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/117186.html