(轉載)原文連接:http://www.javashuo.com/article/p-gbinpznj-z.html
html
在全部後 ES6 時代的數組方法中,我以爲最難理解的就是Array.reduce()
。面試
從表面上看,它彷佛是一個簡單無趣的方法,並無太大做用。 可是在不起眼的外表之下,Array.reduce()
其實是對開發人員工具包的強大而靈活的補充。數組
今天,咱們就來研究一下經過Array.reduce()
能夠完成的一些有意思的事情。瀏覽器
大部分現代的數組方法都返回一個新的數組,而 Array.reduce()
更加靈活。它能夠返回任意值,它的功能就是將一個數組的內容聚合成單個值。服務器
這個值能夠是數字、字符串,甚至能夠是對象或新數組。這就是一直難住個人部分,我沒想到它這麼靈活!ide
Array.reduce()
接受兩個參數:一個是對數組每一個元素執行的回調方法,一個是初始值。函數
這個回調也接受兩個參數:accumulator
是當前聚合值,current
是數組循環時的當前元素。不管你返回什麼值,都將做爲累加器提供給循環中的下一個元素。初始值將做爲第一次循環的累加器。工具
var myNewArray = [].reduce(function (accumulator, current) { return accumulator; }, starting);
讓咱們來看幾個實際例子。post
假設你想把一組數字加在一塊兒。使用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
),以此類推
假設有一個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; }, []);
那麼,若是想建立一個由住在 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>';
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; }, {}); };
還記得前面的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
也很方便實現。
若是你想合併兩個來源的數據到一個對象中,也就是巫師的名字做爲屬性名,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()
工具函數就是個很好的例子。
最後,它應該成爲你的工具箱裏的另外一個工具,一個使用得當就威力無窮的工具。
(轉載)原文連接:http://www.javashuo.com/article/p-gbinpznj-z.html
超值推薦:
阿里雲雙12已開啓,雲產品冰點價,新用戶專享1折起,1核2G雲服務器僅需89元/年,229元/3年。買了對於提高技術或者在服務器上搭建自由站點,都是很不錯的,若是本身有實際操做,面試+工做中確定是加分項。(老用戶能夠用家人或朋友的帳號購買,真心便宜&划算)
可「掃碼」或者「點擊購買 "