tutorial // Dec 23, 2021

How to Use Reduce to Total an Array of Objects in JavaScript

How to use the JavaScript Array.reduce method to loop over an array of items representing a cart, generating an object with a subtotal, tax total, and total (subtotal + tax).

How to Use Reduce to Total an Array of Objects in JavaScript

Getting Started

Because the code we're writing for this tutorial is "standalone" (meaning it's not part of a bigger app or project), we're going to create a Node.js project from scratch. If you don't already have Node.js installed on your computer, read this tutorial first and then come back here.

Once you have Node.js installed on your computer, from your projects folder on your computer (e.g., ~/projects), create a new folder for our work:

Terminal

mkdir reduce

Next, cd into that directory and create an index.js file (this is where we'll write our code for the tutorial):

Terminal

cd reduce && touch index.js

With that, we're ready to get started.

Creating an array of items

The first thing we need to do is create an array of items that will represent our cart. Each item in the cart will have four properties:

  1. id - A unique ID for the item as an integer.
  2. name - A name for the item as a string.
  3. quantity - Quantity of this item being purchased as an integer.
  4. amount - The amount per item as a float (decimal) number.

Let's add an example array to our file. Feel free to play and change this as you see fit (just make sure you use the same key names on each object and the correct data types for the values).

/index.js

const items = [
  { id: 1, name: 'Coffee Maker', quantity: 3, amount: 29.22 },
  { id: 2, name: 'Toaster Oven', quantity: 1, amount: 129.19 },
  { id: 3, name: 'Chef\'s Knife', quantity: 10, amount: 39.38 },
  { id: 4, name: 'Deep Fryer', quantity: 4, amount: 209.61 },
  { id: 5, name: 'Espresso Machine', quantity: 2, amount: 89.49 },
];

Next, before we move on to our reduce function, let's add another variable taxRate to our file which will contain the tax percentage we want to calculate for each item:

/index.js

const items = [
  { id: 1, name: 'Coffee Maker', quantity: 3, amount: 29.22 },
  { id: 2, name: 'Toaster Oven', quantity: 1, amount: 129.19 },
  { id: 3, name: 'Chef\'s Knife', quantity: 10, amount: 39.38 },
  { id: 4, name: 'Deep Fryer', quantity: 4, amount: 209.61 },
  { id: 5, name: 'Espresso Machine', quantity: 2, amount: 89.49 },
];

const taxRate = 0.0625; // 6.25%

Here, like the comment implies, our tax rate will be 6.25%. This is expressed as a float 0.0625.

Using Array.reduce to generate an object

Now that we have some items to work with, we're ready to put .reduce() to work on our array. Let's skeleton out our call first and talk through the end goal.

/index.js

const items = [
  ...
];

const taxRate = 0.0625; // 6.25%

const cart = items.reduce((acc = {}, item = {}) => {
  // We'll handle our calculations here...

  return acc;
}, {
  subtotal: 0,
  tax: 0,
  total: 0
});

console.log(cart);

The important thing to understand about .reduce() is that it's a standard array method in JavaScript, just like .forEach() or .map(). What's unique about .reduce() is that it's designed to loop over an array just like its sibling methods, but instead of just looping over an array (like .forEach()) or looping over an array and returning a modified array (like .map()), it's designed to "reduce an array down to something else."

In cooking, the term "reduce" is used to cook something down into another form (e.g., melting butter together with garlic to create a simple sauce).

Here, we want to "reduce down" our array of items into an object that looks like this:

{
  subtotal: 0,
  tax: 0,
  total: 0,
}

The idea being that for each iteration or "loop" over our array, we add to the values on this object (subtotal, tax, and total), returning that object once we reach the end of the array.

/index.js

const items = [
  ...
];

const taxRate = 0.0625; // 6.25%

const cart = items.reduce((acc = {}, item = {}) => {
  // We'll handle our calculations here...

  return acc;
}, {
  subtotal: 0,
  tax: 0,
  total: 0
});

console.log(cart);

To handle the addition part, to the .reduce() method we pass a function that's called for each iteration or "loop" over our array of items. To that function, two arguments are passed: acc (short for accumulator) and item the current item being looped over.

Here, acc is the object that we ultimately return from our call to .reduce() (in this tutorial, our cart totals). If we look at our call to .reduce() here, we'll notice that the function we just described is the first argument we pass while the starting value for the accumulator (acc) is passed as the second value. Though we're using an object as our starting value, this can technically be any JavaScript value (e.g., a string, integer, or another array).

What we can expect here is that when our .reduce() runs for the first time (meaning it's iterating over the first item in the array, or in our example, the "Coffee Maker" item in the cart), the value of the acc argument passed to the function passed to .reduce() is: { subtotal: 0, tax: 0, total: 0 }.

Our goal is to take that acc and modify it for each iteration or "loop" over our items array, using the current value of item to do so.

/index.js

const items = [
  ...
];

const taxRate = 0.0625; // 6.25%

const cart = items.reduce((acc = {}, item = {}) => {
  const itemTotal = parseFloat((item.amount * item.quantity).toFixed(2));
  const itemTotalTax = parseFloat((itemTotal * taxRate).toFixed(2));

  // We'll modify acc here...

  return acc;
}, {
  subtotal: 0,
  tax: 0,
  total: 0
});

console.log(cart);

Before we modify our acc (accumulator), we need to do some math and formatting for our item. Our goal for each item is to generate two totals: the total for the item itself (its amount multiplied by its quantity) and the amount of tax for that item.

To do it, moving from the inside to the outside, we first multiple the item.amount value with the item.quantity. Because the result of that could produce a long decimal number (e.g., 191.07180001) we wrap that calculation in parentheses and then call the .toFixed(2) method. So it's clear, we're doing this:

(item.amount * item.quantity) // Produces a number which is captured by the parentheses.
(123.2910181).toFixed(2) // Converts the resulting number to a two place decimal number, formatted as a string.

The .toFixed(2) method here is saying "take whatever number was produced from the calculation and convert it to two decimal places." If the third decimal digit is greater than or equal to 5, it will be rounded up (e.g., 123.0157181 will be rounded to 123.02) while a value less than 5 will be rounded down (e.g., 123.014571811 will be rounded to 123.01) by .toFixed().

There's a slight problem you probably guessed: this gives us our number as a string, not as a float (JavaScript dissenters 1, JavaScript developers 0), making our ability to do further calculations difficult.

To get around this, we wrap our (item.amount * item.quantity).toFixed(2) calculation with a call to parseFloat() which, like the name implies, converts whatever value we pass it into a JavaScript float number. So, if we pass something like "123.02", we'll get back an actual float number 123.02.

For itemTotalTax, we use the same exact approach, however, for this number we multiply the itemTotal we just calculated with the taxRate variable we defined earlier.

/index.js

const items = [
  { id: 1, name: 'Coffee Maker', quantity: 3, amount: 29.22 },
  { id: 2, name: 'Toaster Oven', quantity: 1, amount: 129.19 },
  { id: 3, name: 'Chef\'s Knife', quantity: 10, amount: 39.38 },
  { id: 4, name: 'Deep Fryer', quantity: 4, amount: 209.61 },
  { id: 5, name: 'Espresso Machine', quantity: 2, amount: 89.49 },
];

const taxRate = 0.0625; // 6.25%

const cart = items.reduce((acc = {}, item = {}) => {
  const itemTotal = parseFloat((item.amount * item.quantity).toFixed(2));
  const itemTotalTax = parseFloat((itemTotal * taxRate).toFixed(2));

  acc.subtotal = parseFloat((acc.subtotal + itemTotal).toFixed(2));
  acc.tax = parseFloat((acc.tax + itemTotalTax).toFixed(2));
  acc.total = parseFloat((acc.total + itemTotal + itemTotalTax).toFixed(2));

  return acc;
}, {
  subtotal: 0,
  tax: 0,
  total: 0
});

console.log(cart);

Now for the fun part. With our itemTotal and itemTotalTax, we're ready to modify our acc (accumulator). Remember: we're changing acc for every single iteration or "loop" over our items array.

To do it, all we need to do is take the acc argument passed to our function and modify it. Remember: technically speaking acc can contain any value, however, we know that it contains a JavaScript object because of the default value we passed as the second argument to .reduce().

Because of this, we want to modify individual properties on that object. Here, we modify acc.subtotal, acc.tax, and acc.total. For each, notice that we set the value equal to the current value of that property, plus the corresponding total we just calculated (either the item total or the item's tax total).

Notice that in order to keep our numbers fixed to two decimal places, we use the .toFixed(2) combined with parseFloat() trick for each of the totals we set on the object.

Though we only see the final result (this will be stored in the cart variable we've assigned our call to items.reduce() to), if we log out each iteration of our loop, we'd expect to see something like this:

{ subtotal: 0, tax: 0, total: 0 } // Initial value for acc we set as a default.
{ subtotal: 87.66, tax: 5.48, total: 93.14 }
{ subtotal: 216.85, tax: 13.55, total: 230.4 }
{ subtotal: 610.65, tax: 38.16, total: 648.81 }
{ subtotal: 1449.09, tax: 90.56, total: 1539.65 }
{ subtotal: 1628.07, tax: 101.75, total: 1729.82 }

The important part: notice that at the very bottom of the function we pass to .reduce() we make sure to return the acc value after we've modified it. This is required. This is how the .reduce() updates the value of acc after we've modified it.

That's it! Now, for each iteration of our loop we modify acc storing the final result in the variable cart. At the bottom of our file, let's add a console.log(cart) so we can see the output when we run our code.

To run it, in a terminal from the root of our project folder, if we run node index.js we should see something like this log out:

{ subtotal: 1628.07, tax: 101.75, total: 1729.82 }

Wrapping up

In this tutorial, we learned how to use the Array.reduce() method in JavaScript to convert an array of objects into a single object. To demonstrate usage, we created a fictional cart of items and used reduce to calculate the total for each item along with its tax rate.

Written By
Ryan Glover

Ryan Glover

CEO/CTO @ CheatCode