Of all the post-ES6 Array methods, the one I find most difficult to understand is array.reduce ().

On the face of it, it seems like a simple, uninteresting approach that doesn’t do much. But beneath the veneer, array.reduce () is a powerful and flexible addition to the developer toolkit.

Today, we’ll look at some of the interesting things you can do with array.reduce ().

The principle of

While most modern Array methods return a new Array, array.reduce () is more flexible. It can return any value, and its function is to aggregate the contents of an array into a single value.

This value can be a number, a string, or even an object or a new array. This is the part that always stumped me, I didn’t expect it to be so flexible!

usage

Array.reduce() takes two arguments: a callback method for each element of the Array and an initial value.

This callback receives four arguments, the first two being: Accumulator is the current aggregate value and current is the current element of the array loop. Whatever value you return will be provided as an accumulator to the next element in the loop. The initial value will act as an accumulator for the first loop.


var myNewArray = [].reduce(function (accumulator, current) {
  return accumulator;
}, starting);
Copy the code

Let’s look at a few practical examples.

1. Array summing

Suppose you want to add up a set of numbers. Using array.foreach (), you can do something like this:


var total = 0;

[1, 2, 3].forEach(function (num) {
  total += num;
});
Copy the code

This is the most commonly used example of array.reduce (). I found the word * accumulator * confusing, so I changed it to sum in my example because that’s what it means.


var total = [1, 2, 3].reduce(function (sum, current) {
  return sum + current;
}, 0);
Copy the code

We pass in 0 as our initial value.

In the callback, the current value is added to sum, which in the first loop starts at 0, then becomes 1 (initial 0 plus current element value 1), then becomes 3 (cumulative value 1 plus current element value 2), and so on

2. Combine multiple array methods

Suppose there is an array of Wizards:


var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'}];Copy the code

You want to create a new array containing only the names of wizards who live in Hufflepuff. One possible approach is to use the array.filter () method to obtain a wizards whose house property is Hufflepuff. The array.map () method is then used to create a new Array containing only the name attribute of the filtered object.


var hufflepuff = wizards.filter(function (wizard) {
  return wizard.house === 'Hufflepuff';
}).map(function (wizard) {
  return wizard.name;
});
Copy the code

Using the array.reduce () method, we can get the same result in one step, improving performance. Pass an empty array [] as the initial value. Determines whether Wizard. house is Hufflepuff at each loop. If so, add to newArr (Accumulator), otherwise do nothing.

NewArr is returned as accumulator for the next loop regardless of whether the judgment condition is true.


var hufflepuff = wizards.reduce(function (newArr, wizard) {
  if (wizard.house === 'Hufflepuff') {
    newArr.push(wizard.name);
  }
  returnnewArr; } []);Copy the code

3. Generate HTML tags from arrays

So what do you do if you want to create an unordered list of wizards who live in Hufflepuff? Instead of passing an empty Array to array.reduce () as an initial value, an empty string called “” HTML is passed.

If wizard.house equals Hufflepuff, we wrap wizard.name in a list item li and concatenate it into an HTML string. The HTML is then returned as an Accumulator for the next loop.


var hufflepuffList = wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, ' ');
Copy the code

Add the start and end tags to the unordered list before and after array.reduce () to insert it into the DOM.


var hufflepuffList = '<ul>' + wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, ' ') + '</ul>';
Copy the code

4. Grouping array elements

Lodash has a groupBy() method that groups array elements according to some criteria.

Suppose you have an array of numbers.

If you want to group the elements of the numbers array by the value of the integer part, loDash does this:

Var numbers = [6.1, 4.2, 6.3]; / / return {'4': [4.2].'6': [6.1, 6.3]} _. GroupBy (numbers, math.floor);Copy the code

If you have an array of words and you want to group them by the length of the words in the words, you can do this:


var words = ['one'.'two'.'three']; / / return {'3': ['one'.'two'].'5': ['three']}
_.groupBy(words, 'length');
Copy the code

withArray.reduce()implementationgroupBy()function

You can do the same thing with the array.reduce () method.

Let’s create a utility function groupBy() that takes an array and grouping criteria as arguments. Inside groupBy(), array.reduce () is executed on the Array, passing an empty object {} as an initial value, and then returning the result.


var groupBy = function (arr, criteria) {
  return arr.reduce(function(obj, item) {// omit code}, {}); };Copy the code

Inside the array.reduce () callback, we determine whether criteria is an attribute of a function or item. Then get the value of the current item.

If the property does not already exist in obj, it is created and an empty array is assigned to it. Finally, we add item to the array of key and return that object as an Accumulator for the next loop.


var groupBy = function (arr, criteria) {
  return arr.reduce(function(obj, item) {// Determine whether criteria is a function or an attribute'function'? criteria(item) : item[criteria]; // If the attribute does not exist, create oneif(! obj.hasOwnProperty(key)) { obj[key] = []; } // add element to array obj[key]. Push (item); // Return this objectreturn obj;

  }, {});
};
Copy the code

5. Merge data into a single array

Remember the previous Wizards array?


var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'}];Copy the code

If there’s another statistic, the number of points each wizard gets:


var points = {
  HarryPotter: 500,
  CedricDiggory: 750,
  RonaldWeasley: 100,
  HermioneGranger: 1270
};
Copy the code

Suppose you want to combine two pieces of data into an array, adding points values to each wizard object. What would you do?

The array.reduce () method is particularly suitable!


var wizardsWithPoints = wizards.reduce(function(arr, wizard) {// Remove Spaces from wizard names to obtain corresponding points var key = wizard.name. Replace (arr, wizard) {// Remove Spaces from wizard names to obtain corresponding points var key = wizard.name.' '.' '); If the wizard has points, add it, otherwise set it to 0if (points[key]) {
    wizard.points = points[key];
  } else{ wizard.points = 0; } // Add the wizard object to the new array arr.push(wizard); // Return this arrayreturnarr; } []);Copy the code

It’s also easy to implement using array.map.

6. Merge data into a single object

What if you wanted to merge data from two sources into one object, i.e. the wizard’s name as the property name and house and points as the property values? Again, array.reduce () is appropriate.


var wizardsAsAnObject = wizards.reduce(function(obj, wizard) {// Remove the space in the wizard name to obtain the corresponding points var key = wizard.name. Replace (' '.' '); If the wizard has points, add it, otherwise set it to 0if (points[key]) {
    wizard.points = points[key];
  } else{ wizard.points = 0; } // Delete wizard. // add wizard data to new object obj[key] = wizard; // Return this objectreturn obj;

}, {});
Copy the code

Conclusion:Array.reduce()delicious

The array.reduce () method has gone from something I once thought was unusable to one of my favorite JavaScript methods. So, should you use it? When will it be available?

The array.reduce () method has good browser support. All modern browsers support it, including IE9 and above. Mobile browsers have long been supported. If you also need support for older browsers, you can add a Polyfill to support IE6.

The biggest problem with array.reduce () may be that it is a bit confusing to people who have never touched it. The combination of array.filter () and array.map () is slower to execute and contains redundant steps, but is easier to read, and what it does is obvious from the method name.

Sometimes, though, array.reduce () can make complex things seem easier. The groupBy() utility function is a good example.

Finally, it should be another tool in your toolbox, one that is powerful when used properly.

Original text: 24 ways.org/2019/five-i… Translated by 1024 translation station

I have a little request

I have written more than 20 technical articles in The Nuggets. Thanks to everyone’s kindness, I have several articles that have been read more than 10,000 times, and the total number of views has also broken through 100,000. Thank you very much for your golden fingers! However, I also have a small regret. After each article, I left a QR code of my wechat official number 1024 translation station, but I don’t know why there are very few people who pay attention to it. If only 10% of the readers paid attention to each article, I would be laughing in my dreams, haha… It was like my childhood dream: “If everyone in the country gave me a dollar, I would have hundreds of millions!” If it happens, it’s a miracle. Now I have this crazy idea to invite you to create this miracle together! As long as you move your golden finger, pay attention to the next 1024 translation station this public number, you will be able to receive the first time I carefully created technical dry goods! It doesn’t cost a cent! Wechat also recently launched the function of paying for reading, which shows that charging for quality content is a general trend, and there will be less and less free quality content in the future! I have also built a wechat fan group, if a miracle really happens, will love to feedback! Qr code is below, mobile phone sweep, witness the miracle together!