前兩天在羣裏看到一道題,折騰半天沒做出來。今天查了查,瞭解了前因後果,在此整理記錄一下。之前都沒怎麼重視過reduce方法,後來發現它能做的事情還挺多的。
參考資料:
數組的reduce方法
數組的reduce方法相比其他的方法要複雜一些,但理解之後也不難,用法如下:
array.reduce((accumulator, item, index, array) => {
// do something...
}, initialValue)
reduce方法能夠對數組使用,他接受兩個參數,第一個參數是個函數fn
,第二個參數initialValue
爲可選參數,表示累加器的初始值。
而fn
中有4個參數,其參數的值會被initialValue
存在與否所影響:
- 當
initialValue
存在
參數爲:
accumulator
: 累加器,初始值爲initialValue
的值item
:數組的當前項,從第0項開始index
:數組的當前項對應的下標,從0開始array
:數組本身
- 而當
initialValue
不存在
參數爲:
accumulator
: 累加器,初始值爲數組第0項item
:數組的當前項,因爲accumulator
爲第0項,所以這裏從1開始index
:數組的當前項對應的下標,從1開始array
:數組本身
簡單的用例:
//
[0, 1, 2, 3, 4].reduce(function(accumulator, item){
return accumulator + item;
});
compose組合函數
題目:
const fn1 = x => x+1;
const fn2 = x => x+2;
const fn3 = x => x+3;
const fn4 = x => x+4;
let Fn = compose(fn1, fn2, fn3, fn4);
console.log(Fn(0)); // 10
console.log(Fn(5)); // 15
// 求compose函數
compose是redux源碼中使用過的方法。他是函數式編程裏常用的組合函數,和 redux 本身沒有什麼多大關係,先了解下函數式編程的一些概念:
代碼:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
// 這裏注意,因爲reduce沒有傳入第二個參數initValue
// 此時a的初始值爲第0項, b爲第1項
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
其實 compose
函數做的事就是把 var a = fn1(fn2(fn3(fn4(x))))
這種嵌套的調用方式改成 var a = compose(fn1,fn2,fn3,fn4)(x)
的方式調用。
舉一個實際的例子,看看這個函數是怎麼執行的:
const fn1 = x => x+1;
const fn2 = x => x+2;
const fn3 = x => x+3;
const fn4 = x => x+4;
let x = 0
// 假設我這裏想求得這樣的值
let a = fn1(fn2(fn3(fn4(x)))) // 0 + 4 + 3 + 2 + 1 = 10
// 根據compose的功能,我們可以把上面的這條式子改成如下:
let composeFn = compose(fn1, fn2, fn3, fn4)
let b = composeFn(x) // 理論上也應該得到10
看一下compose(fn1, fn2, fn3, fn4)
根據 compose 的源碼, 其實執行的就是: [fn1,fn2,fn3.fn4].reduce((a, b) => (...args) => a(b(...args)))
第幾輪循環 | a的值 | b的值 | 返回的值 |
---|---|---|---|
第一輪循環 | fn1 | fn2 | (…args) => fn1(fn2(…args)) |
第二輪循環 | (…args) => fn1(fn2(…args)) | fn3 | (…args) => fn1(fn2(fn3(…args))) |
第三輪循環 | (…args) => fn1(fn2(fn3(…args))) | fn4 | (…args) => fn1(fn2(fn3(fn4(…args)))) |
循環最後的返回值就是 (...args) => fn1(fn2(fn3(fn4(...args))))
。所以經過 compose
處理過之後,函數就變成我們想要的格式了。
多維數組降維
多維數組降維也可以使用
reduce
結合遞歸來解決
// 極簡版
const flattenDeep = (arr) => Array.isArray(arr)
? arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , [])
: [arr]
// 爲方便理解,寫個註釋版
const flattenDeep = (arr) => {
// 判斷傳入的參數是否是數組
if(Array.isArray(arr)){
// 使用redece
// a的初始值是 [], 對a解構放入結果數組
// 對後邊的每個元素都遞歸執行flattenDeep
// 最後的結果就是,所有不是數組的元素,都被包裹,解構後放入結果數組
// 所有是數組的元素,都遞歸執行了flattenDeep,最終
// 蹭蹭遞歸之後,最終所有都被包裹,解構後放入結果數組
// 也就成了一維數組
arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , [])
}else{
// 當參數不是數組時,包裹成數組(在上邊會解構)
[arr]
}
}