(转载)原文链接:https://juejin.im/post/5dfd9d27e51d455825129ec3

 

在所有后 ES6 时代的数组方法中,我觉得最难理解的就是Array.reduce()

从表面上看,它似乎是一个简单无趣的方法,并没有太大作用。 但是在不起眼的外表之下,Array.reduce()实际上是对开发人员工具包的强大而灵活的补充。

今天,我们就来研究一下通过Array.reduce()可以完成的一些有意思的事情。

原理

大部分现代的数组方法都返回一个新的数组,而 Array.reduce() 更加灵活。它可以返回任意值,它的功能就是将一个数组的内容聚合成单个值。

这个值可以是数字、字符串,甚至可以是对象或新数组。这就是一直难住我的部分,我没想到它这么灵活!

用法

Array.reduce()接受两个参数:一个是对数组每个元素执行的回调方法,一个是初始值。

这个回调也接受两个参数:accumulator是当前聚合值,current是数组循环时的当前元素。无论你返回什么值,都将作为累加器提供给循环中的下一个元素。初始值将作为第一次循环的累加器。


var myNewArray = [].reduce(function (accumulator, current) {
return accumulator;
}, starting);

让我们来看几个实际例子。

1. 数组求和

假设你想把一组数字加在一起。使用Array.forEach()大概可以这么做:


var total = 0; [1, 2, 3].forEach(function (num) {
total += num;
});

这是Array.reduce()用得最多的例子了。我发现* accumulator *这个单词让人困惑,所以在示例中我改为sum,因为这里就是求和的意思。


var total = [1, 2, 3].reduce(function (sum, current) {
return sum + current;
}, 0);

这里传入0作为初始值。

在回调里,将当前值加入到 sum,第一轮循环时它的值是初始值0,然后变成1(初始值0加上当前元素值1),然后变成3(累加值 1加上当前元素值 2 ),以此类推

2. 组合多个数组方法

假设有一个wizards 数组:


var wizards = [
{
name: 'Harry Potter',
house: 'Gryfindor'
},
{
name: 'Cedric Diggory',
house: 'Hufflepuff'
},
{
name: 'Tonks',
house: 'Hufflepuff'
},
{
name: 'Ronald Weasley',
house: 'Gryfindor'
},
{
name: 'Hermione Granger',
house: 'Gryfindor'
}
];

你想创建一个仅包含住在 Hufflepuff 的巫师名字的新数组。一个可行的方法是使用Array.filter() 方法获取 house 属性为Hufflepuff的 wizards 。然后用Array.map() 方法创建一个只包含过滤后对象的name 属性的新数组。


var hufflepuff = wizards.filter(function (wizard) {
return wizard.house === 'Hufflepuff';
}).map(function (wizard) {
return wizard.name;
});

使用Array.reduce() 方法,我们可以用一步得到同样的结果,提高了性能。传递一个空数组[]作为初始值。每次循环时判断wizard.house 是否为Hufflepuff。如果是,就加入到newArr 中(即accumulator),否则啥也不做。

无论判断条件是否成立,最后都返回 newArr 作为下一次循环的accumulator 。


var hufflepuff = wizards.reduce(function (newArr, wizard) {
if (wizard.house === 'Hufflepuff') {
newArr.push(wizard.name);
}
return newArr;
}, []);

3. 从数组生成 HTML 标签

那么,如果想创建一个由住在 Hufflepuff 的巫师组成的无序列表要怎么做呢?这次不是给Array.reduce()传一个空数组作为初始值了,而是一个名为 html的空字符串''

如果wizard.house 等于 Hufflepuff,我们就将wizard.name 用列表项li包裹起来,再拼接到html 字符串里。然后返回html 作为下一次循环的accumulator 。


var hufflepuffList = wizards.reduce(function (html, wizard) {
if (wizard.house === 'Hufflepuff') {
html += '<li>' + wizard.name + '</li>';
}
return html;
}, '');

Array.reduce()前后添加无序列表的开始和结束标记,就可以把它插入到 DOM 中了。


var hufflepuffList = '<ul>' + wizards.reduce(function (html, wizard) {
if (wizard.house === 'Hufflepuff') {
html += '<li>' + wizard.name + '</li>';
}
return html;
}, '') + '</ul>';

4. 数组元素分组

lodash 有个 groupBy()方法,可以将数组元素按照某个标准分组。

假设你有一个数字数组。

如果你想把numbers 数组中的元素按照整数部分的值分组,用 lodash 可以这样做:


var numbers = [6.1, 4.2, 6.3]; // 返回 {'4': [4.2], '6': [6.1, 6.3]}
_.groupBy(numbers, Math.floor);

如果你有一个单词数组,你想根据 words 中的单词长度分组,你可以这样做:


var words = ['one', 'two', 'three']; // 返回 {'3': ['one', 'two'], '5': ['three']}
_.groupBy(words, 'length');

用 Array.reduce() 实现 groupBy()函数

你可以用Array.reduce() 方法实现同样的功能。

我们来创建一个工具函数groupBy(),接受数组和分组条件作为参数。在groupBy()内部,在数组上执行Array.reduce() ,传一个空对象{}作为初始值,然后返回结果。


var groupBy = function (arr, criteria) {
return arr.reduce(function (obj, item) {
// 省略代码
}, {});
};

在 Array.reduce() 回调函数内部,我们会判断criteria是函数还是 item的属性。然后获取当前item的值。

如果obj 中还不存在这个属性,则创建它,并将一个空数组赋值给它。最后,将item 添加到 key的数组中,再返回该对象作为下一次循环的accumulator 。


var groupBy = function (arr, criteria) {
return arr.reduce(function (obj, item) { // 判断criteria是函数还是属性名
var key = typeof criteria === 'function' ? criteria(item) : item[criteria]; // 如果属性不存在,则创建一个
if (!obj.hasOwnProperty(key)) {
obj[key] = [];
} // 将元素加入数组
obj[key].push(item); // 返回这个对象
return obj; }, {});
};

5. 合并数据到单个数组

还记得前面的wizards数组吗?


var wizards = [
{
name: 'Harry Potter',
house: 'Gryfindor'
},
{
name: 'Cedric Diggory',
house: 'Hufflepuff'
},
{
name: 'Tonks',
house: 'Hufflepuff'
},
{
name: 'Ronald Weasley',
house: 'Gryfindor'
},
{
name: 'Hermione Granger',
house: 'Gryfindor'
}
];

如果还有另一份数据,每个巫师获得的的积分对象:


var points = {
HarryPotter: 500,
CedricDiggory: 750,
RonaldWeasley: 100,
HermioneGranger: 1270
};

假设你想把两份数据合并到一个数组,也就是把 points 数值添加到每个巫师对象上。你会怎么做?

Array.reduce() 方法特别适合!


var wizardsWithPoints = wizards.reduce(function (arr, wizard) { // 移除巫师名字中的空格,用来获取对应的 points
var key = wizard.name.replace(' ', ''); // 如果wizard有points,则加上它,否则设置为0
if (points[key]) {
wizard.points = points[key];
} else {
wizard.points = 0;
} // 把wizard对象加入到新数组里
arr.push(wizard); // 返回这个数组
return arr; }, []);

其实这里用Array.map也很方便实现。

6. 合并数据到单个对象

如果你想合并两个来源的数据到一个对象中,也就是巫师的名字作为属性名,house 和 points 作为属性值,要怎么做呢?同样, Array.reduce() 很合适。


var wizardsAsAnObject = wizards.reduce(function (obj, wizard) { // 移除巫师名字中的空格,用来获取对应的 points
var key = wizard.name.replace(' ', ''); // 如果wizard有points,则加上它,否则设置为0
if (points[key]) {
wizard.points = points[key];
} else {
wizard.points = 0;
} // 删除 name 属性
delete wizard.name; // 把 wizard 数据添加到新对象中
obj[key] = wizard; // 返回该对象
return obj; }, {});

总结: Array.reduce() 真香

Array.reduce() 方法从我曾经认为不堪大用的东西,变成我最喜欢的 JavaScript 方法。那么,你应该使用它吗?什么时候可以用?

Array.reduce() 方法有着良好的浏览器支持。所有的现代浏览器都支持,包括 IE9 及以上。移动端浏览器也在很早之前就支持了。如果你还需要支持更老的浏览器,你可以添加一个 polyfill 来支持到 IE6

Array.reduce()最大的槽点可能就是对于从来没接触过的人来说有点费解。组合使用Array.filter() 和Array.map()执行起来更慢,并且包含多余的步骤,但是更容易阅读,从方法名可以明显看出它要做的事情。

尽管如此,有时候Array.reduce() 也可以让复杂的事情看起来更简单。 groupBy() 工具函数就是个很好的例子。

最后,它应该成为你的工具箱里的另一个工具,一个使用得当就威力无穷的工具。

(转载)原文链接:https://juejin.im/post/5dfd9d27e51d455825129ec3

学习地址

超值推荐:

阿里云双12已开启,云产品冰点价,新用户专享1折起,1核2G云服务器仅需89元/年,229元/3年。买了对于提升技术或者在服务器上搭建自由站点,都是很不错的,如果自己有实际操作,面试+工作中肯定是加分项。(老用户可以用家人或朋友的账号购买,真心便宜&划算)

可“扫码”或者“点击购买 "

 

END

 

自从学会了 Array.reduce() ,再也离不开它的更多相关文章

  1. 用es6的Array.reduce()方法计算一个字符串中每个字符出现的次数

    有一道经典的字符串处理的问题,统计一个字符串中每个字符出现的次数. 用es6的Array.reduce()函数配合“...”扩展符号可以更方便的处理该问题. s='abananbaacnncn' [. ...

  2. Array.reduce()学习

    昨天遇到的一道题:1234567890 => 1,234,567,890 要求其实就是使用逗号做千分位将数字进行分隔. 当时没想到任何方法,但是以前看到过,印象很深刻,今天就找了一下. 看到其实 ...

  3. JS Array.reduce 对象属性累加

    Array reduce() 方法  ,无非就是 计算数组元素 相加后的总和 ,看网上给的Demo 全是  [1,2,3,4,6].reduce 这种基本用法, 本次我将使用 reduce 实现 数组 ...

  4. Array.reduce()方法的使用

    起因是学习异步函数的串行与并行写法时,发现reduce方法可以简化写法,然后看到一篇博客里面这样一段代码: var array = [1, [2, [3, 4], 5], 6]; function f ...

  5. Array.reduce()方法

    Array.reduce()方法是对数组的遍历,返回一个单个返回值   使用方法: Array.reduce((acc, cur, idx, src) => { }, initialValue) ...

  6. JavaScrip中 Array.reduce()

    数组的方法 reduce() reduce方法在数组的每一项元素上都会执行回调函数. 语法:array.reduce( callBack [ , init]  ) // 语法arrary.reduce ...

  7. Javascript Array Distinct (array.reduce实现)

    javascript 没有原生的Distinct功能 . (至少现在还没有)但我们可以通过简单的script 自己实现 . Distinct就是把数组中重复出现2次或以上的值给删除掉,确保数组内每个值 ...

  8. 学会这个删库再也不用跑路了~ --技术流ken

    前言 相信每一个学IT的人或多或少都听说过从删库到跑路这个梗~下图也是在各种交流群屡禁不止,新人听着也是瑟瑟发抖. 人们茶余饭后,街头巷角难免要问... 下面技术流ken就教给各位新手们一招删库再也不 ...

  9. 关于Array.reduce的理解与拓展

    2018年1月6日 首先我要感谢我的同事徒步上山看日出在我第一份实习的时候对我的指导,现在我也开始跟他一样开始养成写博客的习惯 现在开始讨论我遇到的第一个问题,这是我在看javascript高级程序设 ...

随机推荐

  1. 太可怕了!黑客是如何攻击劫持安卓用户的DNS?

    最近发现的针对Android设备的广泛路由器的DNS劫持恶意软件现在已升级为针对iOS设备以及桌面用户的功能. 被称为RoamingMantis的恶意软件最初发现在上个月劫持了互联网路由器,以散布旨在 ...

  2. 数据库与缓存:3.mongodb的基本知识

    1. mongodb是什么? NoSQL 非关系型数据库,主要用于数据的海量存储.分为server数据存储端和client数据操作端. 1.1 关系型与非关系型数据库的区别? 1.sql:数据库--表 ...

  3. String、StringBuffer、StringBuilder详解

    String类 字符串广泛应用在java编程中,String类在java.lang包中,String类是final修饰的,不能被继承,String类对象创建后不能修改,由0或多个字符组成,包含在一对双 ...

  4. tomcat启动一闪而过处理

    进入tomcat安装目录(解压目录)下的bin目录,比如D:\Tomcat1\apache-tomcat-7.0.810\bin,打开startup.bat文件,在最上面加上下面两句: SET JAV ...

  5. Python 中内建属性 __getattribute__

    参考自:https://blog.csdn.net/yitiaodashu/article/details/78974596 __getattribute__是属性访问拦截器,就是当这个类的属性被访问 ...

  6. delphi String 与 Stream的互转

    stream1   :=   TStringStream.create(str); str   :=   TStringStream(stream1).DataString; Stream 是抽像类, ...

  7. CTF | bugku | 字符?正则?

    做题链接 一个详细讲正则的网址1 一个详细讲正则的网址2 代码如下 <?php highlight_file('2.php'); $key='KEY{********************** ...

  8. JavaScript实现Word、Excel、PPT在线预览

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_27626333/article/d ...

  9. [CSP-S模拟测试]:kill(二分答案+贪心)

    题目传送门(内部题50) 输入格式 第一行包含四个整数$n,m,s$,表示人数.怪物数及任务交付点的位置.第二行包含$n$个整数$p_1,p_2,...,p_n$.第三行包含$n$个整数$q_1,q_ ...

  10. Cent OS (三)vi文本编辑操作

    序号 命令 命令含义 1 echo            2 vi/vim    编辑 3 cat     cat 命令用于连接文件并打印到标准输出设备上. 4 more   分屏显示文本内容 5 l ...