JavaScript中reduce()方法详解
reduce()方法是JavaScript中很强大的一个方法,很多前端小伙伴都知道这个方法可以用来做数组求和,数组求积等需求,但是对reduce()方法的执行原理却不清楚。这里我们就详细的剖析下JavaScript中reduce()方法的使用,先以数组求和为例,要实现数组求和,在以前,我们需要可能会使用如下的方法来实现:
let ary = [1, 2, 3, 4],
sum = 0;
ary.forEach((item, index) => sum += item)
console.log(sum);
即,我们要先定义一个用来接收最终和的变量,并对其赋初始值0,然后对数组的每一项进行累加。相信这种实现方法大家都能看的懂。接下来我们讲解如何使用reduce()方法来实现数组求和。
reduce()方法,默认接收两个参数,其中第一个参数为一个函数,第二个参数为初始值,为可选参数。其中第一个参数(函数)可接收四个参数,分别为:前一个值、当前项、项目的索引和数组对象。
语法如下:
ary.reduce((prev,cur,index,arr)=>{},init);
参数说明:
- prev 必需。累计器累计回调的返回值; 表示上一次调用回调时的返回值,或者初始值 init;
- cur 必需。表示当前正在处理的数组元素;
- index 可选。表示当前正在处理的数组元素的索引,若提供 init 值,则起始索引为- 0,否则起始索引为1;
- arr 可选。表示原数组; init 可选。表示初始值
为了更好的演示说明,接下来我们分两种情况分别讨论:
一、填写第二个参数:
ary.reduce((prev,cur)=>{
console.log(prev,cur)
},0);
打印结果如下:
0 1
undefined 2
undefined 3
undefined 4
从第二次循环开始,prev变成了undefined,我们在函数中添加return语句,
ary.reduce((prev,cur)=>{
console.log(prev,cur);
return 6;
},0);
则打印结果变为:
0 1
6 2
6 3
6 4
到这一步,我们可以理解,从数组的第二次循环开始,prev的值,来源于方法上次的返回结果值。接下来,我们再改变init初始值为8,进行测试:
ary.reduce((prev,cur)=>{
console.log(prev,cur);
return 6;
},8);
打印结果如下:
8 1
6 2
6 3
6 4
到这一步,相信我们可以从中找到规律了,即在传有init参数时,prev在第一次循环时,其值来源于init设置的初始值,从第二次循环开始,其值来源于上一次循环返回的结果值。那么找到这个规律,我们就可以很好的实现,数组求和了:
let sum = ary.reduce((prev, cur) => {
return prev + cur;
}, 0);
console.log(sum);
二、省略第二个参数:
接下来我们尝试省略第二个参数:
ary.reduce((prev, cur) => {
console.log(prev, cur);
});
打印结果如下:
1 2
undefined 3
undefined 4
发现数组只循环了三次,我们改变原数组,再试一次:
let ary = [8, 9, 3, 4];
ary.reduce((prev, cur) => {
console.log(prev, cur);
});
则打印结果如下:
8 9
undefined 3
undefined 4
这里我们已经可以猜测到大致的规律了,即在不传init初始值的情况下,reduce()方法,默认从第二项开始循环,prev的值为数组第一个值,cur为数组第二个值。
理解到这里,再去对照官方的说明文档,我们就能很容易理解了。需要着重记忆的点是:
1、reduce传入第二个参数,则数组从第一项开始循环,第一次的prev值为第二个参数值。
2、reduce省略第二个参数,则数组从第二项开始循环,第一次的prev值为数组的第一项。
接下来,我们再用图示的形式加强巩固下:
理解了reduce()方法的使用,我们再来看几个需求:
三、练习
3.1 数组求积
let ary = [1, 2, 3];
let multiply = ary.reduce((prev,cur)=>{
return prev * cur;
})
console.log(multiply); // 6
3.2 统计数组中,各元素出现的次数
let ary = ['apple','b','apple','b','orange','apple','red'];
let res = ary.reduce((prev,cur)=>{
if (!prev[cur]){
prev[cur] = 1;
}else{
prev[cur] += 1;
}
return prev;
},[])
console.log(res);
执行代码,返回结果为:
[ apple: 3, b: 2, orange: 1, red: 1 ]
当然,这里的init参数,我们不仅可以设置为空数组,也可以设置为空对象。需要注意的是,在数组第一次循环时,prev的初始值为设置的init参数(空数组或空对象)。
3.3 数组去重
let ary = ['apple', 'b', 'apple', 'b', 'orange', 'apple', 'red'];
let res = ary.reduce((prev, cur) => {
if (prev.indexOf(cur) === -1) prev.push(cur);
return prev;
}, [])
console.log(res);
3.4 数组求最大项
let ary = [1, 2, 0, 5, 8, 9, 1];
let max = ary.reduce((p, c) => {
return Math.max(p, c);
})
console.log(max);
这里需要注意,在实际项目中,我们需要确认数组的每个元素都是纯数字,否则,要进行判断。
- CSS选择器:nth-child()的灵活用法及常见场景示例
CSS选择器中的nth-child()相信大家都比较熟悉,nth-child()和nth-of-type()的区别是:nth-child()不区分类型。大家经常
- 为什么你的logo图模糊不清,移动端图片虚化的解决方案
在传统pc时代的时候,几乎99%的网站都在使用图片格式作为logo,而大部分网站都使用了png透明底的图片来做网站的logo。但是进入移动时代之后,这种习惯还是
- 响应式网站布局的优缺点分析
响应式网站,通俗的讲就是使用CSS媒体查询技术,写一套代码,可以在多个终端上使用。在此之前,前端切图工作者是需要分别针对电脑端、移动端和平板等常见设备专门去写一
- 切图和前端什么关系?为什么前端又被称为切图仔?
很多初从事前端切图这个行业的新人,大多都有一个疑问?为什么要把前端开发人员称为切图仔呢?提起这个问题,我们还要从前端切图行业的发展历程来说起,当然,这个问题对与
- 目前主流的前端框架有哪些?
基本上每种语言都有对应的一些快速框架用于提升开发人员的效率,所谓框架更像是工具箱或者脚手架,在开发时如果能很好的利用框架可以起到事半功倍的效果。简单形象的说,如
- 移动端background-attachment: fixed失效解决方法
在做web前端切图时,我们经常需要做背景图片不跟随内容滚动的效果,这个时候就需要使用到background-attachment: fixed 属性,这个属性及