An overview of the
I have been hovering outside the door of functional programming for a long time. If I want to get started, I have to be familiar with various higher-order functions. The reduce method of arrays is one of them.
The reduce method executes the Reducer function on the array elements from left to right and returns a cumulative value. Take a visual example: you want to build a computer, buy a motherboard, CPU, graphics card, memory, hard disk, power supply… These parts are necessary for assembling a computer.
The assembly process can be summarized as simply removing the packaging of each part and putting it together again. By analogy with reduce function, we can understand that those parts are equivalent to the array of reduce method, and the process of unpacking each part is to perform reducer function on each element of the array. Assembling these parts together is equivalent to the task of Reduce method. The finished computer is equivalent to the return value of the Reduce method.
The reduce method receives two parameters, the first parameter is the reducer callback function and the second parameter is the initial value. The Reducer function receives four parameters:
- Accumulator: MDN is defined as an Accumulator, but I think it is not appropriate. According to my understanding, it should be the result of the reducer function processing the Accumulator until the current element
- Current: the array element currently being executed
- CurrentIndex: Index of the array element currently being executed
- SourceArray: The original array, that is, the array from which the reduce method is called
If a second argument is passed, the reduce method starts cumulative execution based on that argument.
So much about the concept, what is the implementation mechanism of Reduce? Don’t worry, analyze the usage point by point.
Here’s the best example: array summing
const arr = [1, 2, 3, 4]
const accumulator = (total, current, currentIndex, arr) => {
console.log(total, current, currentIndex, arr);
return total + current
}
console.log(arr.reduce(accumulator))
Copy the code
The result is as follows:
Clearly, the end result is to add up all the elements of the array. It is worth noting that it takes the first element of the array as the initial sum and then executes the reducer function on the following elements in turn.
A total of three times to get the final result. So if you pass in initial values, what is the order of execution?
console.log(arr.reduce(accumulator, 3))
Copy the code
The results are as follows:
This time the reducer is followed by the input initial value as the starting point of the summation.
If the reduce method is called on an empty array with no initial value, an error is reported:
Uncaught TypeError: Reduce of empty array with no initial value
Copy the code
Some use
I’ve covered some concepts, but usage scenarios are more important, so here’s a look at how the Reduce approach can be used.
Compose function
Compose is a form of functional programming for combining multiple functions with the return value of the previous function as an input parameter to the current function and the return value of the current function as an input parameter to the next function, somewhat similar to the Onion model of KOA middleware.
[a, b, c, d]
=> a(b(c(d())))
It is essentially the same as summing, except that the summing operation is executed as an input parameter, and the result of the summing becomes the return value of the execution. Redux uses compose in its applyMiddleware to ensure that the final dispatch is the result of all middleware processing.
For example, compose from applyMiddleware:
const result = compose(a, b, c)(params)
Copy the code
The implementation is as follows:
(params) => a(b(c(params)))
Copy the code
Returns a function that takes Params as an entry parameter and is executed from right to left by the first function on the right. The rest of the functions take the return value of the previous function.
Take a look at the implementation:
functioncompose(... Funcs) {// Funcs are the functions that compose is composing, and arg is the argument to the function returned by Componseif(funcs.length === 0) {// If no function is passed in, a function is returned and its return value is the argument passed inreturn arg => arg
}
if(funcs.length === 1) {// If only one function is passed, return the function directlyreturn funcs[0]
}
return funcs.reduce((all, current) => {
return(... args) => {returnall(current(... args)) } }) }Copy the code
Flattening an array
const array = [[0, 1], [2, 3], [4, 5]]
const flatten = arr => {
return arr.reduce((a, b) => {
return a.concat(b)
}, [])
}
console.log(flatten(array)); // [0, 1, 2, 3, 4, 5]
Copy the code
Let’s look at the implementation,
- The first time it is executed, the initial value is passed in
[]
, go to the reduce callback, parameter A is this[]
The argument b is the first item in the array[0, 1]
Within the callback[].cancat([0, 1])
- On the second execution, reduce callback parameter A is the result of the previous callback execution
[0, 1]
Continue to use it for the second item in the concat array[2, 3]
, get the result[0, 1, 2, 3]
Execution continues as parameter A for the next callback execution - . And so on
So suppose the array looks like this? [[0, 111, 222, 1], [2, 333, [444, 555]], 3], [4, 5]], it can add a recursive call
const array = [[0, [111, 222], 1], [2, [333, [444, 555]], 3], [4, 5]]
const flatten = arr => {
return arr.reduce((a, b) => {
if (b instanceof Array) {
return a.concat(flatten(b))
}
return a.concat(b)
}, [])
}
console.log(flatten(array)); // [0, 111, 222, 1, 2, 333, 444, 555, 3, 4, 5]
Copy the code
Counts the number of occurrences of each character in a string
Each time the callback is executed, a key is added to the object, value is the key for the number of occurrences, and value is incremented by 1 if a string has already been stored.
const str = 'adefrfdnnfhdueassjfkdiskcddfjds'
const arr = str.split(' ')
const strObj = arr.reduce((all, current) => {
if (current in all) {
all[current]++
} else {
all[current] = 1
}
return all
}, {})
console.log(strObj) // {"a": 2."d": 7,"e": 2."f": 5,"r": 1,"n": 2."h": 1,"u": 1,"s": 4."j": 2."k": 2."i": 1,"c": 1}Copy the code
Array to heavy
const arr = ['1'.'a'.'c'.'d'.'a'.'c'.'1']
const afterUnique = arr.reduce((all, current) => {
if(! all.includes(current)) { all.push(current) }returnall }, []) console.log(afterUnique); / / /"1"."a"."c"."d"]
Copy the code
Call promises in order
This approach actually handles the value of a promise, treating the value of the previous promise as the value of the next promise.
const prom1 = a => {
return new Promise((resolve => {
resolve(a)
}))
}
const prom2 = a => {
return new Promise((resolve => {
resolve(a * 2)
}))
}
const prom3 = a => {
return new Promise((resolve => {
resolve(a * 3)
}))
}
const arr = [prom1, prom2, prom3]
const result = arr.reduce((all, current) => {
return all.then(current)
}, Promise.resolve(10))
result.then(res => {
console.log(res);
})
Copy the code
implementation
Through the usage above, the characteristics of Reduce can be summarized:
- Accumulator Current CurrentIndex SourceArray Receives two parameters. The first parameter is an Accumulator function. The second parameter is the initial value.
- The return value is the result of all Accumulator executions
Array.prototype.myReduce = function(fn, base) {
if(this.length === 0 && ! base) { throw new Error('Reduce of empty array with no initial value')}for (let i = 0; i < this.length; i++) {
if(! base) { base = fn(this[i], this[i + 1], i, this) i++ }else {
base = fn(base, this[i], i, this)
}
}
return base
}
Copy the code
More technical articles can focus on the public number: a mouthful of a front end