Just a few words

Array.prototype.reduce is a very powerful and interesting Array method. Before I did not learn deeply, I just asked him to do the summation and deal with some simple data. When I dug deeper, I realized that he could do a lot more things, such as concatenating strings, concatenating arrays, filtering and mapping arrays, consolidating objects, and so on.

Here’s a 10-minute, detailed look at what Reduce does, along with some use cases that will allow you to elegantly implement functionality while saving development time and leaving work early [Manual funny].

This section describes reduce parameters

In fact, reduce method receives two parameters, one is the method function [1] for processing iterative data, and the other is the initial value [2]. And then this function that’s passed in is going to make a lot of sense.

[1] Mandatory. This function takes four arguments: the current cumulative value (required), the current traversed value (required), the current traversed index (optional), and the source array (optional).

[2] Optional, pass in a value of any type, representing the value of the initial accumulation. Note that this is an arbitrary type of value, and this is what you need to know to make reduce work.

// Print the parameters of the function so that you can understand them
const arr = [1.1.1];
const initValue = 0;     / / 1)
const result = arr.reduce((total, cur, idx, arr) = > {
    console.log(total, cur, idx, arr);
    return total + cur; / / 2)
}, initValue)
console.log('result => ', result)
// First print:
// 0, 1, 0, [1, 1, 1]

// Print the second time:
// 1, 1, 1, [1, 1, 1]

// Print for the third and final time:
// 2, 1, 2, [1, 1, 1]

// Result print:
// result => 3
Copy the code

Here are a few more details:

First, [2] the initial value can be passed to any type of data, not just the 0 at code 1).

Second, the subsequent cumulative value total is the value returned by the previous Reduce function, as shown in code 2).

Third, when the initial value is not passed, the function will default to the first item of the source array as the initial value. The reason for this is because I have read that the reduce function defaults to undefined if the initial value is not passed, but this is not the case.

[1.2.3].reduce((total, cur) = > {
    console.log('total =>', total);
    return total + cur;
}) // 1) Do not pass "initial value"
// Print in sequence:
// total => 1

// total => 3
Copy the code

In the above code, it prints twice. The first time, instead of undefined, it prints the first item of the array, 1. If an initial value of 0 is passed in, it is printed three times, the first being the initial value of 0. As you can see, if no value is passed to the initial value, then by default the function gets the first item of the array iteration as the initial value.

With that in mind, what can Reduce do

Some reduce applications

Accumulator, the most common and most commonly used should be this, I think I used to simply think that reduce function is only this.

function reduceAdd(arr){
    return arr.reduce((total, cur) = > total + cur);
}
Copy the code

Array flattening

function flatReduce(arr){
    return arr.reduce((pre, cur) = > {
        returnpre.concat(cur); })}console.log(flatReduce([[0.1], [2.3], [4.5]]))// [0, 1, 2, 3, 4, 5]
// Similar to flat
Copy the code

implementationfilter+map

// Both are methods to get an array of ids in an array of objects
const data = [
    {id: 1000.name: 'William'},
    {id: 1001.name: 'Abby'},
    {id: ' '.name: 'skye'}]/ / regular
function badMap(arr){
    const ids = arr.map(item= > item.id); // Get the id array first
    const validIds = ids.filter(id= >id ! = =' ') // Get a non-empty ID
    return validIds;
}
// The above method traverses the array twice, with a time of 2On

// In fact, reduce can achieve the effect of filte and map
function goodMap(arr){
    return arr.reduce((total, {id}) = > {
        returnid ! = =' ' ? [...total, id] : total;
    }, []) // The initial value is passed in as an empty array
}
// The arR is iterated only once, and the time complexity is On
Copy the code

Counts the number of occurrences of each character in a string

function countChar(str = ' '){
    return str.split(' ').reduce((p, k) = > (p[k]++ || (p[k] = 1), p), {});
}
console.log(countChar('aaabbc'));
// {a: 3, b: 2, c: 1}
Copy the code

Concatenate string, development time, may encounter some interface is get request, and then need to manually concatenate GET request parameters, of course, if you use some tool functions can also, here with reduce method implementation

function getParamsForGET(params = {}, url = ' '){
    // Params are object type data, so use es6 entries to get the iterable properties first
    const paramsWrapArr = Object.entries(params); // like [['key', 'value'],...] The data of
    // Use deconstruction to process data more elegantly
    const query = paramsWrapArr.reduce((str, [key, value], idx) = > {
        Const [key, value] = cur; // const [key, value] = cur;
        // get request argument the first argument is used with? Sign separated
        const next = idx === 0 ? `?${key}=${value}` : ` &${key}=${value}`;
        // Concatenate parameters
        return str + next; 
    }, ' ');  // Pass the initial value as an empty string for concatenation
    return url + query;
}
/ / sample
const params = getParamsForGET({wd: 'five o'.foo: 'bar'}, 'baidu.com/s');
// return: baidu.com/s?wd= a wu &foo=bar
Copy the code

Deep object Properties Walk to access the deep properties of an object without having to point and point yourself

function walkInObj(data, keys = []){
    // Keys can accept delimited strings or arrays
    const path = Array.isArray(keys) ? keys : keys.split(/ /, | \. |);
    if(! path.length)return data;
    // The main code
    return path.reduce((pre, cur) = > {
        if(! (curin pre)){
            console.log(`${cur}Properties do not exist in the object. `)
            return pre;
        }else{
            return pre[cur];
        }
    }, data); // The object data is passed in as the initial value, so reduce can access the properties in depth
}
/ / sample
const data = {
    home: {
        furniture: {
            chest: {
                name: 'clothes'}},electric: {
            TV: {
                channel: 'TVB Milky Way'}}}}console.log(
	walkInObj(data, 'home furniture, chest, and the name'),
    walkInObj(data, ['home'.'electric'.'TV'.'channel']))/ / print:
// clothes TVB
Copy the code

It looks like nothing, but as long as a little change can be used to check the validity of some attributes, with the back end of the docking, often encounter some arbitrary back end big man, interface return value is not standard. For example, if you need data from a list field, it is an array type, and no data is returned to an empty array or null. However, I often return an empty string (“) when there is no data, or simply do not give this attribute. (it’s a flaw in p* P’s framework, I don’t know, I’m afraid to ask)

So in order to reduce duplicate code and leave work early and stay away from 996, you can write some methods to check whether the data is valid. For example, here is my common method to check whether the object or value passed from the back end is valid. Now it seems a bit bloated, but the effect is good.

A few last words

The above are just a few uses of the Reduce method. In the workplace, this method can be flexibly used to greatly simplify the code. Some people may think: “OK, I know another thing I might not use”. No, but if you know the details of the method and follow up with a few examples, I’m sure you can claim to have figured it out. When you master a tool, you will unconsciously, unconsciously use him, and when you find that you have used very skilled, and then summed up a similar article with my above words…

The last homework assignment is to implement an array de-duplication function using Reduce. The answer is below, and it’s best to think about it for yourself before scrolling down. OK, that’s it for now.






















// Homework
function unique(arr = []){
    return arr.reduce((total, cur) = >( total.incldues(cur) ? total : [...total, cur]; ) [])},/ / compatible es5
function uniqueProfill(arr){
    var arr = arr || [];
    return arr.reduce(function(total, cur){
        return! ~total.indexOf(cur) ? [...total, cur] : total; }}, [])// Of course my projects are so simple...
function uniqueForce(arr){
    return [...new Set(arr)]
}
Copy the code

Spend ten minutes at a time, understand a front-end knowledge, walk slowly, but continue to walk, enough to make a thousand miles.