Array.prototype.reduce
数组的实例方法
介绍:
- reduce 收敛 把一个数组 转化成 一个值
- 调用:array.reduce(callback, init);
-
callback接收四个参数(当前循环下)
- prev: 初始值 / 数组的前一个元素值
- next:顾名思义,是数组的下一个元素值
- index: 当前next对象的下标
- current: 当前数组
-
init为初始值(optional可选择性传入),callback里的prev会根据是否传入该参数赋值
- 不传时:prev默认指数组的第一个元素值
- 传入时:prev指的是init传入的值,next为数组的第一个元素
// 传入时
let arr1 = [ 1, 2, 3, 4, 5 ];
arr1.reduce((prev, next, index) => {
console.log(prev, next, index);
return prev + next;
}, 2)
// 2 1 0 下标从0开始
// 3 2 1
// 5 3 2
// 8 4 3
// 12 5 4
// 不传时
let arr1 = [ 1, 2, 3, 4, 5 ];
arr1.reduce((prev, next, index) => {
console.log(prev, next, index);
return prev + next;
})
// 1 2 1 下标从1开始
// 3 3 2
// 6 4 3
// 10 5 4
对比上述可见,传入默认值时,数组遍历次数会从第一个元素开始,比不传入时的从第二个元素开始,多遍历一次。
reduce方法实现
Array.prototype.reduce = function(callback, init) {
// 初始化callback的四个参数
let prev, index, next, current = this;
// 判断是否传入callback
if (!callback) throw new Error("undefined is not a function");
// 判断是否传入了init
// undefined/ null 等同于没有传值
if (init == null) {
if (!current.length) throw new Error("Reduce of empty array with no initial value");
prev = current[0];
index = 1;
} else {
prev = init;
index = 0;
}
next = current[index];
try {
while (index < current.length) {
// 每一轮循环都有返回值
prev = callback(prev, next, index, current);
next = current[++index];
}
} catch (error) {
throw error;
}
return prev;
};
// [].reduce(); undefined is not a function
// [].reduce(prev=>{}); // Reduce of empty array with no initial value
// console.log([1, 2, 3].reduce((prev, next) => prev + next, 2)); // 8
console.log([1, 2, 3].reduce((prev, next) => prev + next, 2)); // 8
运用
- 求和
let arr = [ {count: 3, price: 5}, {count: 3, price: 5}, {count: 3, price: 5} ];
let res = arr.reduce((prev, { count, price }) => prev + count * price , 0)
console.log(res); // 45
- compose函数实现 函数返回值作为另一个函数参数的多个函数嵌套调用
实现方法一:reduceRight
function compose(...fns) {
return function (...args) {
let lastFn = fns.pop();
return fns.reduceRight((prev, next) => next(prev), lastFn(...args))
}
}
// 简写:
const compose = (...fns) => (...args) => {
let lastFn = fns.pop();
return fns.reduceRight((prev, next) => next(prev), lastFn(...args))
}
实现方法二:reduce
function compose(...fns) {
return fns.reduce((prev, next) => {
return function (...args) {
return prev((next(...args)))
}
})
}
// 简写
const compose = (...fns) => fns.reduce((prev, next) => (...args) => prev((next(...args))));
// 详解
step 1: 传入(getCurreny, len, sum),进入reduce循环体
第一轮:
prev: getCurreny
next: len
返回return:
function (...args) {
return prev((next(...args)))
} // 作为下一次的prev
第二轮:
prev:
function (...args) {
return getCurreny((len(...args)))
}
next: sum
返回return:
function (...args) {
return function (...args) {
return getCurreny((len(...args)))
}((sum(...args))) // ...args = a, b
}
step 2: 传入(a, b), 执行上述返回的代码
function (a, b) {
return function (...args) {
return getCurreny((len(...args)))
}((sum(a, b))) // ...args = a, b
}
step 3: 函数自执行
function ((sum(a, b)) {
return getCurreny((len((sum(a, b))))
}((sum(a, b))
准备三个函数 相应参数
let sum = (a, b) => a + b;
let len = str => str.length;
let getCurreny = len => `$${len}`;
let a = "hello";
let b = "world";
直接调用
let res = (len(sum(a, b)));
console.log(res); // $10;
compose函数调用
let res = compose(getCurreny, len, sum)(a,b);
console.log(res); // $10;