# 数组的reduce方法好像也挺有趣
# reduce方法的初步认识
let r = []. reduce(function (previousValue, currentValue, currentIndex, arr) {
return previousValue + currentValue
}, 1); // reduce的初始值 会把这个值 传递给previousValue 但是如果空数组,则直接将结果返回
# reduce方法的高级应用
# 1、求分数的平均值 (数组中的每个值都是对象)
// 因为最后返回的平均值是 Number类型,所以reduce的第二个参数为 Number
let r = [
{score:1},
{score:2},
{score:3},
{score:4}
]. reduce((previousValue, currentValue, currentIndex, arr)=>{
if(arr.length-1 === currentIndex){
return (previousValue + currentValue.score )/ arr.length
}
return previousValue + currentValue.score
}, 0);
# 2、数组扁平化 [1, [2, [3, [4, [5]]]]]
// 因为最后的返回值是Array类型,所以reduce的第二个参数为 []
function flatten(arr) {
return arr. reduce((previousValue, currentValue, currentIndex, arr) => {
if (Array.isArray(currentValue)) {
return previousValue.concat(flatten(currentValue))
} else {
previousValue.push(currentValue)
}
return previousValue
}, [])
}
console. log(flatten([1, [2, [3, [4, [5]]]]])) // [1, 2, 3, 4, 5]
# 3、把两个数组合并为一个 对象
let keys = ['name', 'age']
let values = ['zf', 10]
let obj = keys. reduce((memo, current, index) => {
memo[current] = values[index]
return memo
}, {})
console. log(obj) // { name: 'zf', age: 10 }
# 4、JS高阶编程技巧(compose函数实现函数调用扁平化) beta 重点
在项目中我们经常遇到类似的情况,比如一个函数执行完的结果,作为下一个函数的实参
例如:
let fn1 = function (x) {
return x + 10;
};
let fn2 = function (x) {
return x * 10;
};
let fn3 = function (x) {
return x / 10;
};
console. log(fn3(fn1(fn2(fn1(5)))))
重要
如果层级结果较多时,需要函数调用扁平化
函数调用扁平化(compose): 如果是多层级嵌套调用的函数,把一个函数调用完,当作另一个函数的实参传递到下一个函数中
compose函数 原理的执行过程
1、例compose()(5),如compose()函数中无函数参数传递进来,则直接返回后面的参数 5
2、例compose(fn1, fn2, fn1, fn3)(5),先执行fn1(5),再将fn1(5)的结果传递到fn2中,如fn2(fn1(5)) => fn2(15),以此类推fn1(fn2(fn1(5))) => fn1(150),后来每一次函数调用的参数都是前一个函数返回的结果,自然我们就想到了Array. prototype. reduce方法
3、我们需要判断每一次的返回值是否为函数,如为函数需要把... args传递进去,否则把前一次的返回结果传递到下一个函数中去。(实际上对于上面这个例子,只有第一次的x为函数)
扁平化函数 从左向右依次执行
/**
*
* @param {... any} funcs 传递的函数集合
* @param {... any} args 第一次调用函数传递的参数集合
*/
function compose(... funcs) {
return function proxy (... args) {
let len = funcs.length
if (len === 0) return args // 当没传递函数时,直接返回args
if (len === 1) return funcs[0](...args) // 当传来一个函数时,只执行它并返回结果
return funcs.reduce((x, y) => {
// 只有第一次执行时,x的取值是 function,当取出之后,每次返回的x就有了具体的值
return typeof x === 'function' ? y(x(...args)) : y(x)
})
}
}
console. log(compose()(5)); //=>5
console. log(compose(fn1)(5)); //=>5+10 = 15
console. log(compose(fn1, fn2)(5)); //=>fn1(5)=15 fn2(15)=150 ...
console. log(compose(fn1, fn2, fn1, fn3)(5)); //=>16
扁平化函数 从右向左依次执行
function compose(... funcs) {
return function proxy (... args) {
let len = funcs.length
if (len === 0) return args // 当没传递函数时,直接返回args
if (len === 1) return funcs[0](...args) // 当传来一个函数时,只执行它并返回结果
return funcs.reduceRight((x, y) => {
// 只有第一次执行时,x的取值是 function,当取出之后,每次返回的x就有了具体的值
console.log('x',x)
console.log('y',y)
// funcs[len-1](...args) 刚开始让funcs数组中的最后一个函数执行,也就是x的值
return typeof x === 'function' ? y(x(...args)) : y(x)
}, funcs[len-1](...args))
}
}
console. log(compose()(5)); //=>5
console. log(compose(fn1)(5)); //=>5+10 = 15
console. log(compose(fn2, fn1)(5)); //=> x: fn1(5)=15 y:fn1 fn1(15) => 25 ; x: 25 y:fn2 fn2(25) => 250
console. log(compose(fn3, fn1, fn2, fn1)(5));
compose(fn3, fn1, fn2, fn1)(5) 是如何执行的
注意: 当reduce函数中的有第二个参数时,x的初始值为reduce函数第二个参数的值
x: 15 y: fn1 y(x)=25
x: 25 y: fn2 y(x)=250
x: 250 y: fn1 y(x)=260
x: 260 y: fn3 y(x)=26