reduce相关语法
1
| arr.reduce(callbackFn, [initalValue]);
|
callbackFn:reducer函数
包含四个参数:
- previousValue:上一次调用callbackFn的返回值,在第一次调用的时候,如果指定了initalValue,则其值为initalValue,否则为数组索引为0的元素
- currentValue:数组正在处理的元素,在第一次调用的时候,如果指定了initalValue,其值为数组索引为0的元素,否则为数组索引为1的元素
- currentIndex:数组正在处理的元素的索引,如果指定了initalValue,起始索引为0,否则为1
- array:用于遍历的数组
initalValue(可选):
- 第一次调用时作为previousValue的值,这是一个可选的参数
注意点
- reducer不会改变原数组
- reducer中的callbackFn需要返回值(因为需要作为下一次调用的previousValue)
reduce源码实现
实现思路
- 类型检验:回调函数是否对函数,数组是否为空等
- 初始值提供检测,用于确定初始previousValue的值
- 返回累计值
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| Array.prototype.myReduce = function(callbackFn, initalValue) { if (this === null) { throw new TypeError('Array.prototype.reduce called on null or undefined'); }; if (typeof callbackFn !== 'function') { throw new TypeError('Callback must be a function'); }; const obj = Object(this); const lenValue = obj.length; const len = lenValue >>> 0; if (len === 0 && !initalValue) { throw new TypeError('The array contains no elements and initalValue is not provided') }; let k = 0; let accumulator; if (initalValue) { accumulator = initalValue; } else { let kPressent = false; while (!kPressent && k < len) { const pK = String(k); kPressent = obj.hasOwnProperty(pK); if (kPressent) { accumulator = obj[pK]; }; k++; }; if (!kPressent) { throw new TypeError('The array contains error elements'); }; }; while (k < len) { if (k in obj){ accumulator = callbackFn(accumulator, obj[k], k, obj); }; k++; }; return accumulator; };
const arr = [1,2,3,4,5]; const sum = arr.myReduce((prev, curr) => prev+curr, 0); console.log(sum);
|
说明
>>>
表示无符号右移,为了保证结果为非负整数
reduce应用场景
累和&&累积
1 2 3 4
| let arr = [1,2,3,4,5];
let sum = arr.reduce((prev, curr) => prev+curr, 0); let mul = arr.reduce((prev, curr) => prev*curr, 1);
|
求最大值/最小值
1 2 3 4
| let arr = [2,4,7,3,5,8,10,9];
let maxValue = arr.reduce((prev, curr) => Math.max(prev, curr)); let minValue = arr.reduce((prev, curr) => Math.min(prev, curr));
|
数组去重
1 2 3 4 5 6 7 8
| let arr = [3,7,4,2,5,3,2,8];
let newArr = arr.reduce((prev, curr) => { if (prev.indexOf(curr) === -1) { prev.push(curr); }; return prev; }, []);
|
实现map函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Array.prototype.myMap = function(callback) { if(typeof callback === 'function') { return this.reduce((prev, item, index, arr) => { prev.push(callback(item, index, arr)); return prev; }, []) } else { throw new Error('callback is not a fucntion'); }; };
let arr = [1,2,3,4,5]; let newArr = arr.myMap(item => item*2);
|
实现filter函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
Array.prototype.myFilter = function(callback) { if (typeof callback === 'function') { return this.reduce((prev, item, index, arr) => { if (callback(item, index, arr)) { prev.push(item); }; return prev; }, []) } else { throw new Error('callback is not a fucntion'); } };
let arr = [1,2,3,4,5]; let filterArr = arr.myFilter(item => item > 3);
|
实现compose函数
compose函数是指将函数按顺序执行,将若干个函数组合成一个函数来执行,并且每个函数执行的结果都能作为下一个函数的参数
假设有这样两个函数,一个求和函数,一个累积函数
1 2 3 4 5 6 7
| function sum(value) { return value += 20; }
function mul(value) { return value *= 10; };
|
一般情况下,会这样使用:
1 2 3 4
| let value = 10; let res = sum(value); res = mul(res); console.log(res);
|
若是有compose函数,将可以实现以下效果:
1 2 3 4 5 6 7 8 9 10
| const fn = compose(sum, mul); console.log(fn(value));
function compose() { let args = [...arguments]; return function(x) { return args.reduce((prev, curr) => curr(prev),x) }; };
|
按顺序执行Promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| function runPromiseInSequence(arr, input) { return arr.reduce( (promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(input) ) }
function p1(a) { return new Promise((resolve, reject) => { resolve(a * 5) }) }
function p2(a) { return new Promise((resolve, reject) => { resolve(a * 2) }) }
function f3(a) { return a * 3 }
function p4(a) { return new Promise((resolve, reject) => { resolve(a * 4) }) }
const promiseArr = [p1, p2, f3, p4] runPromiseInSequence(promiseArr, 10) .then(console.log)
|
实现数组扁平化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function myFlat(arr, depth) { if (depth < 1) return arr; if (Array.isArray(arr)) { return arr.reduce((prev, cur) => { return Array.isArray(cur) ? prev.concat(myFlat(cur, depth-1)) : prev.concat(cur); }, []) } else { throw new Error('this is not an array'); } };
const arr = [1, 2, [3,4, [5]], [6, 7], [8,[9, [10]]]] myFlat(arr, 2)
|
统计数组元素出现次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function count(arr) { return arr.reduce((prev, curr) => { if (prev.has(curr)) { prev.set(curr, prev.get(curr)+1); } else { prev.set(curr, 1); }; return prev; }, new Map()) };
let arr = [1,2,3,1,2,4,5,6,5,6,1,2,3]; let m = count(arr);
|
使用函数组合实现管道
1 2 3 4 5 6 7 8 9 10
| function increment(input) { return input + 1;} function decrement(input) { return input - 1; } function double(input) { return input * 2; } function halve(input) { return input / 2; }
let pipeline = [increment, double, decrement];
const result = pipeline.reduce(function(total, func) { return func(total); }, 8);
|
知识补充
空值检测
原始值包装类型
参考
MDN reduce
你应该知道的JS: reduce的n种应用
6个关于Reduce() 应用场景的用例
JavaScript之Array.reduce源码解读