Array.prototype.reduce()

简介: Array.prototype.reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

Array.prototype.reduce

JavaScript-Array-Reduce.jpeg


归并类方法 【MDN Docs】


reduce() 方法接收一个函数作为 累加器(accumulator) ,数组中的每个值(从左到右)开始缩减,最终为一个值。


reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,


reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。


接受四个参数: 上一次回调函数的返回值(或者初始值)当前元素值当前索引调用 reduce 的数组


回调函数第一次执行时,accumulatorcurrentValue的取值有两种情况:

  • 如果调用reduce()时提供了initialValueaccumulator取值为initialValuecurrentValue取数组中的第一个值;
  • 如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。


所以,如果没有提供 initialValue ,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。


如果提供 initialValue ,从索引0开始。


如果数组为空且没有提供 initialValue ,会抛出TypeError 。


如果数组仅有一个元素(无论位置如何)并且没有提供 initialValue , 或者有提供 initialValue 但是数组为空,那么此唯一值将被返回并且callback不会被执行。


一般来说,提供初始值通常更安全。


constmaxCallback= (acc, cur) => {
console.log(acc, cur);
return { x: Math.max(acc.x, cur.x) };
};
constmaxCallback1= (acc, cur) => {
console.log(acc, cur);
returnMath.max(acc.x, cur.x);
};
constmaxCallback2= (acc, cur) => {
console.log(acc, cur);
returnMath.max(acc, cur);
};
// reduce() 没有初始值// 注意分配给累加器的返回值的形式[{ x: 2 }, { x: 22 }, { x: 42 }].reduce(maxCallback1); // NaN[{ x: 2 }, { x: 22 }].reduce(maxCallback1); // 22[{ x: 2 }].reduce(maxCallback1); // { x: 2 }[].reduce(maxCallback1); // Uncaught TypeError: Reduce of empty array with no initial value// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行[{ x: 22 }, { x: 42 }].map((el) =>el.x).reduce(maxCallback2, -Infinity);



1 求和

constsumlist= [1, 3, 5, 7, 9, 11, 13];
constinitVal=0;
// 第二次循环方法中prev的值,是第一次循环方法返回的结果。functionitercb(prev, curVal, curIndex, arr) {
// console.log("先前值:", prev);// console.log("累加值:", curVal, ", 下标:", curIndex);returnprev+curVal;
}
consttotal=sumlist.reduce(itercb, initVal);
console.log("sum total:", total);



2 滤重

constrepeatList= ["a", "aa", "aaa", "a", "a", "aa", "aaa", "aaaa", "aaa"];
functioncbRepeat(prev, curVal, curIndex) {
if (prev.includes(curVal)) {
// 若包含,则不添加returnprev;
  } else {
// 添加return [...prev, curVal];
  }
}
constresult=repeatList.reduce(cbRepeat, []);
console.log("result:", result); // ['a', 'aa', 'aaa', 'aaaa']// anotherconstarr= [1, 2, 3, 4, 4, 1];
constnewArr=arr.reduce((prev, cur) => {
if (prev.indexOf(cur) ===-1) {
returnprev.concat(cur);
  } else {
returnprev;
  }
}, []);
console.log(newArr); // [1, 2, 3, 4]

各滤重方法的性能疑问

constmyArray= ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
console.time("indexOf");
letmyOrderedArray=myArray.reduce(function (accumulator, currentValue) {
if (accumulator.indexOf(currentValue) ===-1) {
accumulator.push(currentValue);
  }
returnaccumulator;
}, []);
console.timeEnd("indexOf"); // indexOf: 0.02685546875 msconsole.log(myOrderedArray);
console.time("sort");
letresult=myArray.sort().reduce((init, current) => {
if (init.length===0||init[init.length-1] !==current) {
init.push(current);
  }
returninit;
}, []);
console.timeEnd("sort"); // sort: 0.06787109375 msconsole.log(result); // [1,2,3,4,5]console.time("set");
letorderedArray=Array.from(newSet(myArray));
console.timeEnd("set"); // set: 0.006103515625 msconsole.log(orderedArray);


3 计数

constnames= ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
// {Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}constnameNum=names.reduce((prev, cur) => {
// in 如果指定的属性在指定的对象或其原型链中,返回true// in 右操作数必须是一个对象值,可以是 new String(),但不能是 '',删除delete和赋值undefined是不一样的结果if (curinprev) {
prev[cur]++;
  } else {
prev[cur] =1;
  }
returnprev;
}, {});
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}

【in 操作符】 

in运算符用来判断对象是否拥有给定属性。

类比includes,判断数组是否拥有给定值。


【MDN 表达式和运算符】



for ... in & for ... of

constarr= ["a", "b", "c"];
constobj= { a: "aaa", b: "bbb", c: "ccc" };
for (letiinarr) {
console.log(i); // 下标,索引值 0,1,2}
for (letiofarr) {
console.log(i); // 元素值 a,b,c}
for (letiinobj) {
console.log(i); // name,非value a,b,c}
for (letiofobj) {
console.log(i); // 报错,obj is not iterable}
// 总结:// 对象只能用 for in 遍历,数组可以用 for in 和 for of 遍历// for in 遍历能获取 index 或 name,for of 遍历能拿到数组元素值// 只能foa 不能foo// fia fio 皆可,都是获取索引(index或name)



4 对象里的属性求和

varresult= [
  {
subject: "math",
score: 10,
  },
  {
subject: "chinese",
score: 20,
  },
  {
subject: "english",
score: 30,
  },
];
varsum=result.reduce(function (prev, cur) {
returnprev+cur.score;
}, 0);
console.log(sum); // 60



5 多维数组转一维

constarr= [
  [1, 2],
  [
    [3, 4, [5, 6, 7], 8],
    [9, 10],
  ],
11,
  [12, 13, [14, 15]],
];
constflttenArr= (arr) => {
returnarr.reduce((prev, cur) => {
returnprev.concat(Array.isArray(cur) ?flttenArr(cur) : cur);
  }, []);
};
flttenArr(arr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]



6 按顺序运行promise

functionrunPromiseInSequence(arr, input) {
returnarr.reduce((promiseChain, currentFunction) => {
/*     * 1、Promise {<fulfilled>: 10}     * 2、Promise {<fulfilled>: 50}     * 3、Promise {<fulfilled>: 100}     * 4、Promise {<fulfilled>: 300}     */console.log("acc:", promiseChain);
/*     * 1、p1     * 2、p2     * 3、f3     * 4、p4     */console.log("cur:", currentFunction);
returnpromiseChain.then(currentFunction);
  }, Promise.resolve(input));
}
// promise function 1functionp1(a) {
returnnewPromise((resolve, reject) => {
resolve(a*5);
  });
}
// promise function 2functionp2(a) {
returnnewPromise((resolve, reject) => {
resolve(a*2);
  });
}
// function 3  - will be wrapped in a resolved promise by .then()functionf3(a) {
returna*3;
}
// promise function 4functionp4(a) {
returnnewPromise((resolve, reject) => {
resolve(a*4);
  });
}
constpromiseArr= [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10).then(console.log); // 1200



7 管道运算

constdouble= (x) =>x+x;
consttriple= (x) =>x*3;
constquardple= (x) =>x*4;
constpipe=  (...functions) =>  (initVal) =>functions.reduce((acc, cur) => {
returncur(acc);
    }, initVal);
constmultiply4=pipe(double, double);
constmultiply6=pipe(double, triple);
constmultiply8=pipe(double, quardple);
constmultiply9=pipe(triple, triple);
constmultiply12=pipe(triple, quardple);
constmultiply16=pipe(quardple, quardple);
constmultiply24=pipe(double, triple, quardple);
multiply4(10);
multiply6(10);
multiply8(10);
multiply9(10);
multiply12(10);
multiply16(10);
multiply24(10);



利用reduce实现map

constarr= [1, 3, 5, 7, 9];
constnewMappedArr=arr.map((item) =>item*item);
console.log(newMappedArr); // [1, 9, 25, 49, 81]// thisArg可选 执行 callback 函数时值被用作this。// 不能使用箭头函数,没有thisArray.prototype.mapByReduce=function (cb, thisArg) {
returnthis.reduce((acc, cur, index, arr) => {
acc[index] =cb.call(thisArg, cur, index, arr);
returnacc;
  }, []);
};
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/mapconstnewMRArr=arr.mapByReduce((item) =>item*3);
console.log(newMRArr);



Polyfill

// Production steps of ECMA-262, Edition 5, 15.4.4.21// Reference: http://es5.github.io/#x15.4.4.21// https://tc39.github.io/ecma262/#sec-array.prototype.reduceif (!Array.prototype.reducee) {
// 往 Array.prototype 对象上定义reduce属性,可被调用Object.defineProperty(Array.prototype, "reducee", {
// 其值为函数value: function (callback/*, initialValue*/) {
// this 为 reduce 方法的调用者,即某个数组if (this===null) {
thrownewTypeError(
"Array.prototype.reduce "+"called on null or undefined"        );
      }
if (typeofcallback!=="function") {
thrownewTypeError(callback+" is not a function");
      }
// 1. Let O be ? ToObject(this value).// Object 构造函数将给定的值包装为一个新对象。this为null或undefined时,o={}varo=Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).// >>> 按位无符号右移运算符varlen=o.length>>>0; // 保证是个数字,可以将结果undefined变为0// Steps 3, 4, 5, 6, 7vark=0; // 即下标indexvarvalue; // 累加器,每次迭代的终值// 参数长度大于等于2if (arguments.length>=2) {
// 参数列表第一个是回调函数,第二个是 初始值 initialValuevalue=arguments[1];
      } else {
// 正常有值数组,len>0,对象o中不存在k索引 ??? 排除无效的o属性while (k<len&&!(kino)) {
k++;
        }
// 3. If len is 0 and initialValue is not present,//    throw a TypeError exception.// 空数组 & 无初始值if (k>=len) {
thrownewTypeError(
"Reduce of empty array "+"with no initial value"          );
        }
value=o[k++];
      }
// 8. Repeat, while k < len 一直遍历到最后一个数while (k<len) {
// a. Let Pk be ! ToString(k).// b. Let kPresent be ? HasProperty(O, Pk).// c. If kPresent is true, then//    i.  Let kValue be ? Get(O, Pk).//    ii. Let accumulator be ? Call(//          callbackfn, undefined,//          « accumulator, kValue, k, O »).if (kino) {
// 记得我们给的callback里,函数最后要return,不然value就拿不到值了value=callback(value, o[k], k, o);
        }
// d. Increase k by 1.k++;
      }
// 9. Return accumulator.returnvalue;
    },
  });
}
目录
相关文章
|
JavaScript 对象存储
wangEditor接入阿里云OSS
wangEditor接入阿里云OSS
548 0
|
JSON 开发工具 git
工作五年多,idea插件推荐(一)
工作五年多,idea插件推荐(一)
|
7月前
|
JavaScript 前端开发 UED
PDF在线预览实现:如何使用vue-pdf-embed实现前端PDF在线阅读
本文详细介绍了如何在Vue项目中使用vue-pdf-embed实现PDF文件的在线展示。从项目初始化、插件集成到高级功能的实现和部署优化,希望对你有所帮助。在实际项目中,灵活运用这些技术可以大大提升用户体验和项目质量。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
云安全 安全 Linux
钓鱼特辑(二)在红队眼皮底下拆解木马
一场牵动人心的攻防演练正在如火如荼地开展,红方每天变着花样对目标进行钓鱼攻击,亿格云枢EDR也捕获到诸多木马样本:如XX市场业务部招聘jd&福利“、个人简历docx.rar、VX截图_20240731.exe 、图片文件-XXX公司相关问题咨询20240730.zip....
|
11月前
|
数据采集 搜索推荐 算法
语义化的 HTML 对 SEO 的好处具体体现在哪些方面?
【10月更文挑战第24天】语义化的 HTML 通过提升搜索引擎对网页的理解能力、优化关键词匹配、增强页面结构清晰度以及提高网站整体质量评估等多个方面,为网站的 SEO 带来了显著的好处,有助于提高网站的可见性、流量和排名,从而实现更好的网络营销效果。
260 9
|
11月前
|
前端开发 JavaScript
JS-instanceof 的实现原理
`instanceof` 运算符在前端 JavaScript 中用于检测对象的原型链是否包含指定构造函数的 `prototype` 属性。它通过遍历对象的原型链来实现。每个对象都有一个内部链接 `[[Prototype]]` 指向其原型对象,当访问属性或方法时,JavaScript 引擎会沿着原型链查找。`instanceof` 的具体实现是通过比较对象的原型链中的原型与构造函数的 `prototype` 属性,直到找到匹配的原型或到达原型链的顶端。示例代码展示了如何使用 `instanceof` 检查对象的继承关系。此外,`instanceof` 可用于验证继承关系和类型检查,支持多态性。
|
移动开发 数据安全/隐私保护 UED
HTML5 新的 Input 类型详解
HTML5引入了多种新输入类型,显著提升了表单的用户体验和可用性。这些类型包括普通文本、搜索、电子邮件、网址、电话号码、密码、数字、范围选择、日期、时间、颜色选择等,每个类型都有特定用途和优化功能。例如,`email` 类型可自动验证邮件格式,`number` 类型提供增减按钮,而 `date` 类型则内置日期选择器。这些新类型不仅简化了用户操作,还增强了开发者对表单验证和数据交互的控制能力。
|
JSON 前端开发 JavaScript
使用vite搭建一个React项目!真香!
【8月更文挑战第13天】使用vite搭建一个React项目!真香!
2115 3
使用vite搭建一个React项目!真香!
|
人工智能 算法
算法金 | 平均数、众数、中位数、极差、方差,标准差、频数、频率 一“统”江湖
**统计学江湖概要** - **平均数(均值)**:数字的总和除以数量,代表集中趋势,如分赃时平均分配。 - **众数**:出现次数最多的数字,反映了最常见的值,如同一招式被频繁使用。 - **中位数**:排序后位于中间的值,反映数据的中心位置,如同武者武功的中等水平。 - **极差**:最大值减最小值,表示数据波动范围,类似武功最高与最低的差距。 - **方差**:衡量数据波动性,计算每个数值与均值差的平方和的平均数。 - **标准差**:方差的平方根,同单位的波动度量。 - **频数**:某个值出现的次数,如统计武器使用情况。 - **频率**:频数与总次数的比例,显示出现的相对频率。
477 2
算法金 | 平均数、众数、中位数、极差、方差,标准差、频数、频率 一“统”江湖
|
JavaScript
TypeScript——Record类型
TypeScript——Record类型
183 0