(转载)原文链接: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. springBoot+mysql+mybatis demo [基本配置] [遇到的问题]

    springBoot+mysql+mybatis的基本配置: 多环境 application.properties spring.profiles.active=dev spring.applicat ...

  2. MetaException(message:For direct MetaStore DB connections, we don't support retries at the client level.)

    在mysql中执行以下命令:  drop database hive;  create database hive;  alter database hive character set latin1 ...

  3. UVA10779 Collectors Problem 【迁移自洛谷博客】

    这是一道不错的练最大流建模的基础题. 这种题目审题是关键. Bob's friends will only exchange stickers with Bob, and they will give ...

  4. 25.Java锁的深度化

    Java锁的深度化 悲观锁.乐观锁.排他锁 场景 当多个请求同时操作数据库时,首先将订单状态改为已支付,在金额加上200,在同时并发场景查询条件下,会造成重复通知. SQL: Update 悲观锁与乐 ...

  5. IntelliJ IDEA 代码调式

    Mute Breakpoints: 保留所有断点,但是不执行(程序一次性执行). Condition: 条件触发 即当执行到i的值变为5的时候,在断点处暂停.

  6. 常用生物信息 ID 及转换方法

    众多不同的数据库所采用的对 Gene 和 Protein 编号的 ID 也是不同的, 所以在使用不同数据库数据的时候需要进行 ID 转换. 常用数据库 ID ID 示例 ID 来源 ENSG00000 ...

  7. Request Payload 和 Form Data 的区别

    概述 我正在开发的项目前端和后端是完全独立的,通过配置 webpack 的 proxy 将前端请求跨域代理到后台服务.昨天发现,我前端执行 post 请求,后台 springmvc 的 @Reques ...

  8. exists 的简单介绍

    准备数据: CREATE TABLE Books( BookID number, BookTitle VARCHAR2(20) NOT NULL, Copyright varchar2(20) ) I ...

  9. PHP数据如何向上取整

    PHP数据如何向上取整? PHP数据向上取整可以通过ceil()函数来实现,ceil()函数表示向上舍入为最接近的整数. 语法是: 1 ceil(x) 参数 x 必需.一个数. 说明 返回不小于 x ...

  10. Python基础教程(015)--Python2默认不支持中文

    前言 Python2默认不支持中文 内容 市场上有Python2,和Python3, Python2的解释器不支持中文. 用Python3来运行文件. 错误信息 SyntaxError:Non-ASC ...