reduce
是ES5中新引入的一個API。javascript
假如你還不知道reduce的用法,請先閱讀下MDN文檔中關於reduce的介紹。(不得不說,MDN文檔太強大了,裏面列舉了不少有用的方法)java
本文將介紹藉助reduce函數,利用其可以遍歷到數組的每個元素,而且次遍歷均可以使用上次遍歷結果的特性,實現的一些功能。編程
1.累和/累積
函數式編程
let arr = [1, 2, 3, 4, 5]
console.log(arr.reduce((prev, cur) => prev + cur)) // 15數組
複製代碼// 能夠實現另類的階乘 console.log(arr.reduce((prev, cur) => prev * cur)) // 120 複製代碼複製代碼
2.求最大值/最小值
let arr = [1, 2, 3, 4, 5]
console.log(arr.reduce((prev, cur) => Math.max(prev, cur))); // 5
console.log(arr.reduce((prev, cur) => Math.min(prev, cur))); // 1
複製代碼複製代碼
3. 數組去重
當reduce
接收兩個參數時,即reduce(fn, init), init
將做爲fn
的第一個參數prev
傳入。函數
這裏,將一個空數組[]
做爲去重後的新數組,經過作判斷,若是該容器內已經存在某元素,就啥也不作;反之,若是該容器內尚未一個元素,就將其推入容器。post
ui
let arr = [1, 2, 3, 1, 1, 2, 3, 3, 4, 3, 4, 5]
let res = arr.reduce((prev, cur)=>{
!prev.includes(cur) && prev.push(cur)
return prev
}, [])
複製代碼console.log(res) // [ 1, 2, 3, 4, 5 ] 複製代碼複製代碼
4.實現map函數
map
函數接收一個函數做爲參數,做爲參數的函數接收三個參數值,分別是遍歷數組的每一項元素,元素的索引和數組自己。這三個參數恰好和reduce
函數接收的第一個函數參數的第二、三、4個參數是對應的。this
實現思路是,將每次遍歷的元素,做爲傳入的函數的參數,並將函數執行的結果放入新的數組中。spa
let arr = [1, 2, 3]
Array.prototype._map = function(cb) {
if(typeof cb === 'function') {
// this: 調用_map方法的當前數組對象
let arr = this;
return arr.reduce((prev, item, index, array) => {
prev.push(cb(item, index, array))
return prev
}, [])
} else {
throw new Error(cb + ' is not function')
}
}
複製代碼let res = arr._map(n => n*2) console.log(res) // [ 2, 4, 6 ] 複製代碼複製代碼
5.實現filter函數
實現filter
的思路和實現map
是一致的,只不事後者是一股腦的把執行結果全放入數組中,而filter
須要作一個判斷:若是filter
函數傳入的參數(參數是一個函數)執行後有返回值,即通過了檢驗,纔將遍歷的當前元素放入數組中,若是沒有返回值,就忽略。
let arr = [1, 2, 3, 4, 5];
Array.prototype._filter = function(cb) { if(typeof cb === 'function') { let arr = this; return arr.reduce((prev, item, index, array) => { cb(item, index, array) ? prev.push(item) : null return prev }, []) } else { throw new Error(cb + ' is not function') } }
複製代碼let res = arr._filter(n => n>2) console.log(res) // [ 3, 4, 5 ] 複製代碼複製代碼
6.實現compose
compose
是函數式編程的核心思想,簡單說就是將若干個函數組合成一個函數來執行,而且每一個函數執行的結果都能做爲下一個函數的參數。這也是使用reduce
實現compose
的思路。
假設有兩個函數,做用分別是將字符串轉爲大寫,在字符串末尾追加感嘆號:
function toUpperCase(str) {
return str.toUpperCase();
}
複製代碼function add(str) { return str += '!' } 複製代碼複製代碼
通常狀況下,會這樣使用:
var str = 'hello world'
var res = toUpperCase(str)
res = add(res)
console.log(res); // HELLO WORLD!
複製代碼複製代碼
使用compose
後,效果是這樣的,執行fn
,至關於依次執行了toUpperCase
和add
:
var fn = compose(add, toUpperCase)
console.log(fn(str));// HELLO WORLD!
複製代碼複製代碼
接下來實現一下compose
:
function compose() {
let args = [].slice.call(arguments)
return function (x) {
// 由於compose()接收的函數參數,是從右往走順次執行的,
// 因此這裏使用reduceRight, 用法和reduce一致,只不過是從右往左遍歷數組。
return args.reduceRight((prev, cur) => {
return cur(prev)
}, x)
}
}
複製代碼複製代碼
7.數組扁平化
數組扁平化,針對的是多維數組,將其扁平、展開,成爲一維數組。
let arr = [1, 2, '3js', [4, 5, [6], [7, 8, [9, 10, 11], null, 'abc'], {age: 12}, [13, 14]], '[]'];
function flatten(arr) { if(Array.isArray(arr)) { return arr.reduce((prev, cur) => { // 若是遍歷的當前項是數組,再迭代展平 return Array.isArray(cur) ? prev.concat(flatten(cur)) : prev.concat(cur) }, []) } else { throw new Error(arr + ' is not array') } }
複製代碼console.log(flatten(arr)); 複製代碼複製代碼
結束
固然,除了以上幾種,reduce
還有更多種神奇的應用,等待着各位小夥伴的發現和使用。