数组的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]
	}
}




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