哈Ha! 我向您介绍克里斯· 费迪南迪( Chris Ferdinandi )的文章“使用Array.reduce()的五种有趣方式(以及一种无聊的方式)”的翻译。
在使用数组的所有现代方法中,我必须使用的最困难的方法是Array.reduce()。
乍一看,这似乎是一种简单,无聊的方法,几乎没有效果。 但是,尽管外观不大,但Array.reduce()是您开发人员工具集的强大而灵活的补充。
今天,让我们看一下可以使用Array.reduce()做的一些有趣的事情。
Array.reduce()如何工作
大多数现代数组方法都会返回一个新数组。 Array.reduce()方法更加灵活。 他可以退还任何东西。 其目的是获取一个数组并将其内容压缩为一个值。
该值可以是数字,字符串,甚至是对象或新数组。 这是一直困扰我的部分-我不知道它有多灵活!
句法
Array.reduce()具有两个参数:回调方法(用于启动数组中的每个元素)和初始值initialValue。
回调也有两个参数:累加器(它是当前的组合值)和currentValue循环中的当前项。 您返回的所有内容都将用作循环中下一个元素的累加器。 第一个循环使用初始值代替。
var myNewArray = [].reduce(function (accumulator, current) { return accumulator;}, starting); }, starting);
让我们看一些例子。
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()的示例陈词滥调。 “累加器”一词令人困惑,因此在此示例中,我们将其称为“求和”,因为它是固有的。
var total = [1, 2, 3].reduce(function (sum, current) { return sum + current; }, 0); 0 .
在回调中,我们将当前值添加到第一个循环中初始值为0的数量,然后是1(初始值0加元素值1),然后是3(总值1加元素值2),依此类推。
一个例子。
2,一步一步组合Array.map()和Array.filter()数组方法
想象一下,霍格沃茨有很多巫师。
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()方法仅返回那些在家中具有Hufflepuff属性的向导。 然后,我们使用Array.map()方法创建一个仅包含其余母版的name属性的新数组。
// var hufflepuff = wizards.filter(function (wizard) { return wizard.house === 'Hufflepuff'; }).map(function (wizard) { return wizard.name; });
使用Array.reduce()方法,您可以一次性获得相同的数组,这将提高我们的性能。 我们传递一个空数组([])作为初始值。 每次通过时,我们都要检查一下Wizard.house是否是赫奇帕奇。 如果是这样,请将其发送到newArr(在此示例中为我们的累加器)。 如果没有,则什么也不做。
无论如何,都返回newArr以在下一遍中获取累加器。
// var hufflepuff = wizards.reduce(function (newArr, wizard) { if (wizard.house === 'Hufflepuff') { newArr.push(wizard.name); } return newArr; }, []);
一个例子。
3,从数组创建标记
如果不是要创建一个名称数组,而是要在赫奇帕奇中创建一个无序的母版列表怎么办? 而不是将Array.reduce()中的空数组作为初始值,而是传递一个空字符串('')并将其称为html。
如果Wizard.house等于Hufflepuff,我们将html字符串与包含在开始和结束列表元素(li)中的Wizard.name组合。 然后在下一个循环中将HTML作为累加器返回。
// 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()方法,该方法将元素的集合作为数组,并根据某些条件将它们分组为对象。
假设我们需要一个数字数组。
如果我们想将所有元素按其整数值分组为数字,则应使用lodash进行。
var numbers = [6.1, 4.2, 6.3]; // returns {'4': [4.2], '6': [6.1, 6.3]} _.groupBy(numbers, Math.floor);
如果有一个单词数组,并且您需要按单词的长度对元素进行分组,则可以这样做。
var words = ['one', 'two', 'three']; // returns {'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) { // Some code will go here... }, {}); };
在Array.reduce()内部,我们调用回调函数以检查条件是应用于元素的函数还是元素的属性。 然后我们从当前元素中获取它的值。
如果对象尚不具有此值的属性,则创建它[property]并将一个空数组分配为其值。 最后,向该属性添加一个元素,并将该对象作为下一个循环的累加器返回。
var groupBy = function (arr, criteria) { return arr.reduce(function (obj, item) { // , // var key = typeof criteria === 'function' ? criteria(item) : item[criteria]; // , . if (!obj.hasOwnProperty(key)) { obj[key] = []; } // obj[key].push(item); // return obj; }, {});};
演示完成的助手功能。
特别感谢Tom Bremer的帮助。 可以在Vanilla JS Toolkit中找到该辅助功能以及更多其他功能。
5.将来自两个来源的数据合并到一个数组中
回顾我们的向导列表。
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 };
想象一下,我们想将两组数据合并到一个数组中,并在向导数组中的每个向导的数据中添加点数。 怎么做?
Array.reduce()方法非常适合!
var wizardsWithPoints = wizards.reduce(function (arr, wizard) { // points, // var key = wizard.name.replace(' ', ' '); // , , // 0. if (points[key]) { wizard.points = points[key]; } else { wizard.points = 0; } // wizard . arr.push(wizard); // . return arr; }, []);
将两个来源的数据合并到一个数组中的示例 。
6.将来自两个来源的数据合并到一个对象中
相反,如果有必要将两个数据源组合成一个对象,其中每个向导的名称为键,而他们的房屋和眼镜为属性,该怎么办? 同样,Array.reduce()方法非常适合此操作。
var wizardsAsAnObject = wizards.reduce(function (obj, wizard) { // points, // var key = wizard.name.replace(' ', ' '); // , , // 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()是一个很好的例子。
最终,这是您工具箱中的另一个工具。 如果使用得当,可以赋予超能力的工具。
关于作者
克里斯·费迪南迪(Chris Ferdinandi)帮助人们学习普通JavaScript。 他认为,有一种更简单,更可靠的方法来为Internet做事。
克里斯是《 香草JS袖珍指南》系列的作者,《 香草JS学院》课程的创建者以及《 香草JS播客》的演示者。 每个工作日都有成千上万的开发人员阅读其开发人员咨询通讯 。
他在Chobani和Boston Globe等组织中培训了开发人员,他的JavaScript插件被Apple和哈佛商学院使用。 CSS-Tricks和CodePen的创始人Chris Coyer将他的工作描述为“被无休止地引用”。
克里斯热爱海盗,幼犬和皮克斯电影,也住在马萨诸塞州乡村的养马场附近。 他与贝利小狗一起带领Go Make Things 。