數組的reduce方法及其應用

前兩天在羣裏看到一道題,折騰半天沒做出來。今天查了查,瞭解了前因後果,在此整理記錄一下。之前都沒怎麼重視過reduce方法,後來發現它能做的事情還挺多的。

參考資料:

數組的reduce方法

數組的reduce方法相比其他的方法要複雜一些,但理解之後也不難,用法如下:

array.reduce((accumulator, item, index, array) => {
	// do something...
}, initialValue)

reduce方法能夠對數組使用,他接受兩個參數,第一個參數是個函數fn,第二個參數initialValue爲可選參數,表示累加器的初始值。

fn中有4個參數,其參數的值會被initialValue存在與否所影響:

  • initialValue存在

參數爲:

  1. accumulator: 累加器,初始值爲initialValue的值
  2. item:數組的當前項,從第0項開始
  3. index:數組的當前項對應的下標,從0開始
  4. array:數組本身
  • 而當initialValue不存在

參數爲:

  1. accumulator: 累加器,初始值爲數組第0項
  2. item:數組的當前項,因爲 accumulator爲第0項,所以這裏從1開始
  3. index:數組的當前項對應的下標,從1開始
  4. 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]
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章