一:reduce介绍
1.1:基本语法
array. reduce ( function ( total, currentValue, currentIndex, arr ) , initialValue)
1.2:工作流程
1.设置初始值:如果你给了initialValue,它会作为total的初始值;如果没给,数组的第一个元素会作为初始值
2.迭代处理:reduce从初始值开始(或者数组的第一个/第二个元素),逐个处理每个currentValue,并把结果累加到total
3.完成迭代:数组处理完了,reduce就会返回累加后的最终结果
1.3:求和案例
假设你有一个数组[1, 2, 3, 4],你想算出这个数组中所有数字的和
const sum = [ 1 , 2 , 3 , 4 ] . reduce ( function ( total, currentValue ) {
return total + currentValue;
} , 0 ) ;
console. log ( sum) ;
二:基础使用场景
1.1:计算数组的总和
const prices = [ 5 , 12 , 3 , 7 , 10 ] ;
const totalAmount = prices. reduce ( ( total, price ) => total + price, 0 ) ;
console. log ( totalAmount) ;
1.2:数组元素的拼接
const lyrics = [ "I" , "love" , "coding" , "with" , "JavaScript" ] ;
const sentence = lyrics. reduce ( ( total, word ) => total + " " + word) ;
console. log ( sentence) ;
1.3:找到数组中的最大值
const scores = [ 45 , 85 , 72 , 93 , 66 ] ;
const highestScore = scores. reduce ( ( max, score ) => Math. max ( max, score) , - Infinity ) ;
console. log ( highestScore) ;
三:进阶用法
1.1:扁平化数组
一个装满了小盒子的大盒子,而这些小盒子里又装着更小的盒子。你的任务是把所有的小盒子里的物品全部倒出来,放到一个平面上这就是“扁平化”操作
function Flat ( arr = [ ] ) {
return arr. reduce ( ( total, currentValue ) => total. concat ( Array. isArray ( currentValue) ? Flat ( currentValue) : currentValue) , [ ] ) ;
}
const nestedFiles = [ 0 , 1 , [ 2 , 3 ] , [ 4 , 5 , [ 6 , 7 ] ] , [ 8 , [ 9 , 10 , [ 11 , 12 ] ] ] ] ;
console. log ( Flat ( nestedFiles) ) ;
reduce:就像把大盒子一层层打开。
Array.isArray(currentValue):检查当前拿到的是否还是一个小盒子(数组)。
Flat(currentValue):如果是小盒子,再递归地把它打开,直到拿出所有物品(非数组元素)。
concat:把这些物品一个个放到我们铺开的平面上(结果数组)。
1.2:分割数组——分页显示商品列表
想象你在打包一批商品,每个包裹只能装固定数量的商品。当一个包裹装满时,你就开始打包下一个包裹。最终,你会得到一系列整齐的包裹,每个包裹里都有固定数量的商品。这就是我们要做的“分页显示”
function Chunk ( arr, size ) {
return arr. length ? arr. reduce ( ( total, currentValue ) => ( total[ total. length - 1 ] . length === size ? total. push ( [ currentValue] ) : total[ total. length - 1 ] . push ( currentValue) , total) , [ [ ] ] ) : [ ] ;
}
const products = [ 1 , 2 , 3 , 4 , 5 ] ;
console. log ( Chunk ( products, 2 ) ) ;
reduce:就像在打包商品。
total[total.length - 1]:这是当前正在打包的包裹。
total[total.length - 1].length === size:检查当前包裹是否装满。
push:如果满了,开始一个新的包裹;如果没满,把商品继续装入当前包裹。
1.3:统计出现次数
想象你在统计每个用户点击了多少次按钮,就像在记录每个用户按下不同按钮的次数。每次用户点击按钮,你就在一个记录本上对应的按钮旁边记下一笔,最后你就可以知道每个按钮被点击了多少次
function Counting ( arr ) {
return arr. reduce ( ( total, currentValue ) => {
total[ currentValue] = ( total[ currentValue] || 0 ) + 1 ;
return total;
} , { } ) ;
}
const userActions = [ 'click' , 'scroll' , 'click' , 'hover' , 'click' ] ;
console. log ( Counting ( userActions) ) ;
reduce:就像在帮你统计每个事件的发生次数。
total[currentValue]:这是记录本上对应事件的计数。
total[currentValue] || 0:如果这个事件还没被记录过,就初始化为0。
+1:每次事件发生,就在对应的计数上加1。
1.4:查找元素位置
想象你在一堆订单中寻找那些出了问题的订单(比如状态为“异常”),就像在一份名单中标记出所有异常订单的位置,以便后续处理
function Position ( arr, val ) {
return arr. reduce ( ( total, currentValue, currentIndex ) => {
if ( currentValue. status === val) {
total. push ( currentIndex) ;
}
return total;
} , [ ] ) ;
}
const orders = [
{ id : 1 , status : 'completed' } ,
{ id : 2 , status : 'pending' } ,
{ id : 3 , status : 'exception' } ,
{ id : 4 , status : 'exception' }
] ;
console. log ( Position ( orders, 'exception' ) ) ;
reduce:就像在浏览订单列表,每找到一个符合条件的订单,就记下它的位置。
currentValue.status === val:检查当前订单是否是“异常”状态。
push(currentIndex):如果是异常订单,就把它的位置(索引)记录下来
1.5:组合函数——订单折扣计算
想象你在为用户计算订单总价,这个过程就像在制作一道美味的菜肴,需要按顺序添加各种配料(折扣、会员优惠、税费)。每一步都对最终的味道(价格)有影响,最后得到的是用户需要支付的总价。
const addDiscount = ( x ) => x - 5 ;
const applyMemberDiscount = ( x ) => x * 0.9 ;
const addTax = ( x ) => x + ( x * 0.08 ) ;
const composedFunctions = [ addDiscount, applyMemberDiscount, addTax] ;
const finalPrice = composedFunctions. reduce ( ( total, currentValue ) => currentValue ( total) , 100 ) ;
console. log ( finalPrice) ;
composedFunctions:这里的数组就像一系列步骤,每一步都对订单总价进行处理。
reduce:依次执行每个步骤,把当前的价格传给下一个处理函数。
100:初始的订单价格。
finalPrice:经过所有处理后的最终订单价格。
1.6:数组去重——数据清洗中的重复项去除
function Uniq ( arr ) {
return arr. reduce ( ( total, currentValue ) => total. includes ( currentValue) ? total : [ ... total, currentValue] , [ ] ) ;
}
const rawData = [ 2 , 1 , 0 , 3 , 2 , 1 , 2 ] ;
console. log ( Uniq ( rawData) ) ;
reduce:就像一个过滤器,遍历数组中的每个元素。
total.includes(currentValue):检查当前元素是否已经存在于结果数组中。
total:如果当前元素已经存在,就跳过;否则,把它加到结果数组中。
1.7:计算平均值
function Average ( arr ) {
return arr. reduce ( ( total, currentValue, currentIndex, array ) => {
total += currentValue;
if ( currentIndex === array. length - 1 ) {
return total / array. length;
}
return total;
} , 0 ) ;
}
const ratings = [ 4 , 5 , 3 , 4 , 5 ] ;
console. log ( Average ( ratings) ) ;
reduce:就像一个评分收集器,遍历每个用户的评分。
total += currentValue:把每个评分累加到总分里。
if (currentIndex === array.length - 1):在最后一个评分加完后,计算平均值。
total / array.length:总分除以评分人数,得到平均分。 • reduce:就像一个评分收集器,遍历每个用户的评分。
total += currentValue:把每个评分累加到总分里。
if (currentIndex === array.length - 1):在最后一个评分加完后,计算平均值。
total / array.length:总分除以评分人数,得到平均分。
1.8:找最大值和最小值
function Max ( arr = [ ] ) {
return arr. reduce ( ( total, currentValue ) => total > currentValue ? total : currentValue) ;
}
function Min ( arr = [ ] ) {
return arr. reduce ( ( total, currentValue ) => total < currentValue ? total : currentValue) ;
}
const prices = [ 120 , 450 , 210 , 650 , 380 ] ;
console. log ( Max ( prices) ) ;
console. log ( Min ( prices) ) ;
Max函数:通过遍历数组,记住当前看到的最大值。
Min函数:同样遍历数组,记住当前看到的最小值。
reduce:在遍历过程中比较每个值,并更新最大值或最小值
1.9 URL 参数解析——处理用户请求中的查询参数
搜索功能,当用户在搜索框中输入条件并提交时,URL会包含这些查询参数。你需要把这些参数拆解开,放到一个对象里,这样你就可以用它们来执行搜索查询。reduce方法可以帮你轻松完成这一步
function ParseUrlSearch ( str ) {
return str. replace ( / (^\?)|(&$) / g , "" ) . split ( "&" ) . reduce ( ( total, currentValue ) => {
const [ key, val] = currentValue. split ( "=" ) ;
total[ key] = decodeURIComponent ( val) ;
return total;
} , { } ) ;
}
const url = 'key1=value1&key2=value2&key3=value3' ;
console. log ( ParseUrlSearch ( url) ) ;
replace(/(^?)|(&$)/g, ""):去掉URL中的问号或其他特殊符号,留下纯参数部分。
split("&"):将参数字符串按“&”分隔成一个数组,每个元素是一个“key=value”的形式。
reduce:遍历这个数组,把每个“key=value”解析成键值对,存入一个对象中。
decodeURIComponent(val):对参数值进行解码,以防止URL编码问题
2.0 URL 参数序列化——生成API请求参数
function StringifyUrlSearch ( search ) {
return Object. entries ( search) . reduce (
( total, currentValue ) => ` ${ total} ${ currentValue[ 0 ] } = ${ encodeURIComponent ( currentValue[ 1 ] ) } & ` ,
Object. keys ( search) . length ? "?" : ""
) . replace ( / &$ / , "" ) ;
}
const params = { foo : "bar" , baz : 42 } ;
console. log ( StringifyUrlSearch ( params) ) ;
Object.entries(search):将对象转换为一个二维数组,每个元素是一个[key, value]对,方便遍历。
reduce:遍历每个参数对,将它们拼接成“key=value”的形式,并用“&”连接。
encodeURIComponent(currentValue[1]):对参数值进行编码,确保特殊字符在URL中合法。
replace(/&$/, ""):去掉最后一个多余的“&”符号,使查询字符串格式正确
2.1:对象分组——按属性分组用户数据
用户的某个属性(比如年龄)将他们分组,这样可以更方便地进行统计和分析。reduce方法就像一个分类器,帮你把用户按照指定的属性归类到不同的组里
function Grouping ( arr, key ) {
return arr. reduce ( ( total, currentValue ) => {
if ( ! total[ currentValue[ key] ] ) {
total[ currentValue[ key] ] = [ ] ;
}
total[ currentValue[ key] ] . push ( currentValue) ;
return total;
} , { } ) ;
}
const users = [
{ name : 'Alice' , age : 25 } ,
{ name : 'Bob' , age : 30 } ,
{ name : 'Charlie' , age : 25 } ,
{ name : 'Dave' , age : 30 }
] ;
console. log ( Grouping ( users, 'age' ) ) ;
reduce:就像在整理用户数据,根据指定的属性(比如年龄)将用户归类。
total[currentValue[key]]:检查当前分类组是否已经存在,如果不存在,就创建一个新的数组来存放这一组用户。
push(currentValue):将用户添加到对应的分组中。
2.2: 创建查找表——快速查找产品信息
根据产品ID就能快速找到对应的产品信息。reduce方法可以帮你把产品数组转换为这样的查找表
function arrayToMap ( arr, key ) {
return arr. reduce ( ( total, currentValue ) => {
total[ currentValue[ key] ] = currentValue;
return total;
} , { } ) ;
}
const products = [
{ id : 1 , name : 'Laptop' , price : 999 } ,
{ id : 2 , name : 'Phone' , price : 699 } ,
{ id : 3 , name : 'Tablet' , price : 499 } ,
] ;
const productMap = arrayToMap ( products, 'id' ) ;
console. log ( productMap) ;
reduce:遍历产品数组,逐一处理每个产品。
total[currentValue[key]] = currentValue:将产品的ID作为查找表的键,产品的详细信息作为对应的值,存入查找表。
total:最终形成一个以产品ID为键,产品信息为值的对象,方便快速查找
2.3:合并数组为对象——将表单字段与值配对
字段名和用户输入的值配对,形成一个对象,以便提交给后端处理。reduce方法可以帮你将这两个数组合并成一个对象
function Merge ( arr1, arr2 ) {
return arr1. reduce ( ( total, currentValue, index ) => {
total[ currentValue] = arr2[ index] ;
return total;
} , { } ) ;
}
const fields = [ 'name' , 'age' , 'gender' ] ;
const values = [ 'Alice' , 25 , 'female' ] ;
console. log ( Merge ( fields, values) ) ;
reduce:遍历字段数组arr1,逐一处理每个字段。
total[currentValue] = arr2[index]:将字段名作为对象的键,将对应的用户输入值作为值,添加到对象中。
index:通过索引匹配字段名和对应的输入值。