Array.prototype.reduce has not been used much in the past. I asked this question in the byteDance interview, and then I went to see MDN to understand it a little bit
usage
The reduce method passes each element of the array from left to right in turn to the callback function
👇 are some of the common places
Counts the number of occurrences of each character in a string
Method 1 (this is the most common method I use without array.prototype.reduce):
const str = '9kFZTQLbUWOjurz9IKRdeg28rYxULHWDUrIHxCY6tnHleoJ'
const obj = {}
str.split(' ').forEach(item= > {
obj[item] ? obj[item]++ : obj[item] = 1
})
Copy the code
Method 2 (this is a little fun 🤪):
const str = '9kFZTQLbUWOjurz9IKRdeg28rYxULHWDUrIHxCY6tnHleoJ'
const obj = {}
Array.from(str).reduce((accumulator, current) = > {
current in accumulator ? accumulator[current]++ : accumulator[current] = 1
return accumulator
}, obj)
Copy the code
Well, method 2 although the steps are more complicated than method 1 (actually not complicated roar), but is it more fun 😉?
Filters data in an array that meets multiple criteria at once
Method 1 (Common):
const arr = [
{
"name": "a1111"."age": 25
},
{
"name": "a1"."age": 26
},
{
"name": "a11"."age": 27
},
{
"name": "a"."age": 29
},
{
"name": "a11"."age": 29
},
{
"name": "a11"."age": 26
},
{
"name": "a111"."age": 25
},
{
"name": "a11"."age": 26
},
{
"name": "a1"."age": 26
},
{
"name": "a"."age": 26
}
]
arr.filter(item= > item.name.length === 3)
.filter(item= > item.age > 26)
/* [ { "name": "a11", "age": 27 }, { "name": "a11", "age": 29 } ] */
Copy the code
Method 2 Reduce method (thanks for @Zhanggenming’s proof, modified):
const arr = [
{
"name": "a1111"."age": 25
},
{
"name": "a1"."age": 26
},
{
"name": "a11"."age": 27
},
{
"name": "a"."age": 29
},
{
"name": "a11"."age": 29
},
{
"name": "a11"."age": 26
},
{
"name": "a111"."age": 25
},
{
"name": "a11"."age": 26
},
{
"name": "a1"."age": 26
},
{
"name": "a"."age": 26}]const filter1 = (arr) = > arr.filter(item= > item.name.length === 3)
const filter2 = (arr) = > arr.filter(item= > item.age > 26)
const fnArr = [filter1, filter2]
fnArr.reduce((accumulator, fn) = > {
accumulator = fn(accumulator)
return accumulator
}, arr)
/* [ { "name": "a11", "age": 27 }, { "name": "a11", "age": 29 } ] */
Copy the code
With this approach, let’s try implementing array.prortotype.reduce with a for loop
Let’s look at the parameters that Reduce receives:
arr.reduce(callback[, initialValue])
Copy the code
The reduce method takes a callback function as its first argument, along with an optional initialValue. The callback function also takes up to four arguments
- The return value of an accumulator callback; It is the cumulative value returned when the callback was last called. If initialValue is provided, its default value is initialValue, otherwise it is the first value of the array
- CurrentValue Specifies the element currently participating in the calculation
- CurrentIndex Array index of the current evaluated element
- Array Array of the current operation
With this in mind, implementing the Reduce approach is straightforward
Array.prototype.selfReduce = function() {
const ary = this
const { length } = ary
if (arguments.length === 0) {
throw new TypeError('undefined is not a function')}if (typeof arguments[0]! = ='function') {
throw new TypeError(arguments[0] + 'is not a function')}if (ary.length === 0 && arguments.length === 1) {
throw new TypeError('Reduce of empty array with no initial value')}const callback = arguments[0]
const startIndex = arguments.length >= 2 ? 0 : 1
let value = startIndex === 0 ? arguments[1] : ary[0]
for (let i = startIndex; i < length; i++) {
value = callback(value, ary[i], i, ary)
}
return value
}
Copy the code
At the same time,reduce also has its brother 👬reduceRight, which, as its name suggests, passes each element of an array from right to left into a callback function. That realization reduceRight realization is also simple.
Array.prototype.selfReduceRight = function () {
const ary = this
const { length } = ary
if (arguments.length === 0) {
throw new TypeError('undefined is not a function')}if (typeof arguments[0]! = ='function') {
throw new TypeError(arguments[0] + 'is not a function')}if (ary.length === 0 && arguments.length === 1) {
throw new TypeError('Reduce of empty array with no initial value')}const startIndex = arguments.length >= 2 ? length - 1 : length - 2
const callback = arguments[0]
let value = startIndex === 0 ? arguments[1] : ary[length - 1]
for (let i = startIndex; i >= 0; i--) {
value = callback(value, ary[i], i, ary)
}
return value
}
Copy the code
Write in the last
A little bit of functional programming (FP)
- Compose (combination)
- Pipe (pipe)
compose
Compose executes from right to left
Here is the implementation of compose (unhandled exceptions)
const compose = function(. fns) {
return (val) = > {
return fns.reduceRight((acc, fn) = > {
return fn(acc);
}, val)
}
};
const add1 = x= > x + 1;
const mult2 = y= > y * 2;
const composeFn = compose(add1, mult2);
composeFn(5); // 11 = 5 * 2 + 1
Copy the code
pipe
Like the inside of the Unix “|”, execution of the pipe from left to right. The following is a very simple command to view the nginx process (written a little bit 😂).
ps -ef | grep nginx
Copy the code
Here is the implementation of PIPE (unhandled exception case)
const pipe = function(. fns) {
return (val) = > {
return fns.reduce((acc, fn) = > {
return fn(acc);
}, val)
}
};
const add1 = x= > x + 1;
const mult2 = y= > y * 2;
const pipeFn = pipe(add1, mult2);
pipeFn(5); // 12 = (5 + 1) * 2
Copy the code