自從學會了 Array.reduce() ,再也離不開它


(轉載)原文鏈接: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM