Sådan bruges Reducer til total en række objekter i JavaScript

Sådan bruges JavaScript Array.reduce-metoden til at sløjfe over en række varer, der repræsenterer en vogn, og generere et objekt med en subtotal, momstotal og total (subtotal + moms).

Kom godt i gang

Fordi koden, vi skriver til denne tutorial, er "standalone" (hvilket betyder, at den ikke er en del af en større app eller et større projekt), vil vi oprette et Node.js-projekt fra bunden. Hvis du ikke allerede har Node.js installeret på din computer, skal du først læse denne vejledning og derefter vende tilbage hertil.

Når du har Node.js installeret på din computer, fra din projektmappe på din computer (f.eks. ~/projects ), opret en ny mappe til vores arbejde:

Terminal

mkdir reduce

Dernæst cd ind i den mappe og opret en index.js fil (det er her, vi skriver vores kode til selvstudiet):

Terminal

cd reduce && touch index.js

Dermed er vi klar til at komme i gang.

Oprettelse af en række elementer

Den første ting, vi skal gøre, er at skabe en række varer, der repræsenterer vores indkøbskurv. Hver vare i kurven vil have fire egenskaber:

  1. id - Et unikt ID for elementet som et heltal.
  2. name - Et navn for elementet som en streng.
  3. quantity - Mængden af ​​denne vare, der købes, som et heltal.
  4. amount - Beløbet pr. vare som et flydende (decimal) tal.

Lad os tilføje et eksempel-array til vores fil. Du er velkommen til at spille og ændre dette, som det passer dig (bare sørg for at bruge de samme nøglenavne på hvert objekt og de korrekte datatyper for værdierne).

/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 },
];

Dernæst, før vi går videre til vores reducere-funktion, lad os tilføje en anden variabel taxRate til vores fil, som vil indeholde den afgiftsprocent, vi ønsker at beregne for hver vare:

/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%

Her vil vores skatteprocent, som kommentaren antyder, være 6,25%. Dette er udtrykt som en float 0.0625 .

Brug af Array.reduce til at generere et objekt

Nu hvor vi har nogle elementer at arbejde med, er vi klar til at sætte .reduce() at arbejde på vores array. Lad os skelet vores opkald først og tale igennem slutmålet.

/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);

Det vigtige at forstå om .reduce() er, at det er en standard array-metode i JavaScript, ligesom .forEach() eller .map() . Hvad er unikt ved .reduce() er, at det er designet til at sløjfe over et array ligesom dets søskendemetoder, men i stedet for blot at sløjfe over et array (som .forEach() ) eller sløjfe over et array og returnere et modificeret array (som .map() ), den er designet til at "reducere en matrix til noget andet."

I madlavning bruges udtrykket "reducere" til at koge noget ned i en anden form (f.eks. smelte smør sammen med hvidløg for at skabe en simpel sauce).

Her ønsker vi at "reducere" vores række af genstande til et objekt, der ser sådan ud:

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

Ideen er, at vi for hver iteration eller "loop" over vores array tilføjer værdierne på dette objekt (subtotal , tax og total ), returnerer det objekt, når vi når slutningen af ​​arrayet.

/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);

For at håndtere tilføjelsesdelen, til .reduce() metode vi sender en funktion, der kaldes for hver iteration eller "loop" over vores række af elementer. Til den funktion sendes to argumenter:acc (forkortelse for akkumulator) og item det aktuelle element, der løkkes.

Her acc er det objekt, som vi i sidste ende returnerer fra vores opkald til .reduce() (i denne vejledning er vores indkøbskurv samlet). Hvis vi ser på vores opkald til .reduce() her vil vi bemærke, at den funktion, vi lige har beskrevet, er det første argument, vi sender, mens startværdien for akkumulatoren (acc ) overføres som den anden værdi. Selvom vi bruger et objekt som vores startværdi, kan dette teknisk set være hvilket som helst JavaScript-værdi (f.eks. en streng, heltal eller en anden matrix).

Det, vi kan forvente her, er, at når vores .reduce() kører for første gang (hvilket betyder, at den itererer over det første element i arrayet, eller i vores eksempel "Kaffemaskine"-elementet i kurven), værdien af ​​acc argument sendt til funktionen videregivet til .reduce() er:{ subtotal: 0, tax: 0, total: 0 } .

Vores mål er at tage den acc og modificer den for hver iteration eller "loop" over vores items array ved hjælp af den aktuelle værdi af item at gøre det.

/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);

Før vi ændrer vores acc (akkumulator), skal vi lave noget matematik og formatering for vores element. Vores mål for hver vare er at generere to totaler:totalen for selve varen (dens amount ganget med dens quantity ) og afgiftsbeløbet for den pågældende vare.

For at gøre det, flytter vi fra indersiden til ydersiden, multiplicerer vi først item.amount værdi med item.quantity . Fordi resultatet af det kunne producere et langt decimaltal (f.eks. 191.07180001 ) vi pakker den beregning i parentes og kalder derefter .toFixed(2) metode. Så det er klart, vi gør dette:

(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.

.toFixed(2) metode her er at sige "tag det tal, der blev produceret fra beregningen, og konverter det til to decimaler." Hvis det tredje decimalciffer er større end eller lig med 5, vil det blive rundet op (f.eks. 123.0157181 vil blive afrundet til 123.02 ), mens en værdi mindre end 5 vil blive rundet ned (f.eks. 123.014571811 vil blive afrundet til 123.01 ) af .toFixed() .

Der er et lille problem, som du sikkert har gættet:dette giver os vores nummer som en streng, ikke som en flyder (JavaScript-forskere 1, JavaScript-udviklere 0), hvilket gør vores evne til at udføre yderligere beregninger vanskelig.

For at omgå dette pakker vi vores (item.amount * item.quantity).toFixed(2) beregning med et opkald til parseFloat() som, som navnet antyder, konverterer den værdi, vi sender den til et JavaScript-float-nummer. Så hvis vi sender noget som "123.02" , får vi et faktisk flydende nummer 123.02 tilbage .

For itemTotalTax , vi bruger den samme nøjagtige tilgang, men for dette tal multiplicerer vi itemTotal vi har lige beregnet med taxRate variabel, vi definerede tidligere.

/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);

Nu til den sjove del. Med vores itemTotal og itemTotalTax , vi er klar til at ændre vores acc (akkumulator). Husk:vi ændrer acc for hver enkelt iteration eller "loop" over vores items matrix .

For at gøre det skal vi bare tage acc argumentet videregivet til vores funktion og ændre det. Husk:teknisk set acc kan indeholde en hvilken som helst værdi, men vi ved, at den indeholder et JavaScript-objekt på grund af standardværdien, vi sendte som det andet argument til .reduce() .

På grund af dette ønsker vi at ændre individuelle egenskaber på det pågældende objekt. Her ændrer vi acc.subtotal , acc.tax og acc.total . Bemærk for hver af dem, at vi sætter værdien lig med aktuel værdien af ​​den pågældende ejendom, plus den tilsvarende total, vi lige har beregnet (enten varens samlede værdi eller varens momstotal).

Bemærk, at for at holde vores tal fast til to decimaler, bruger vi .toFixed(2) kombineret med parseFloat() trick for hver af de totaler, vi sætter på objektet.

Selvom vi kun ser det endelige resultat (dette vil blive gemt i cart). variabel, vi har tildelt vores opkald til items.reduce() til), hvis vi logger ud af hver iteration af vores loop, ville vi forvente at se noget som dette:

{ 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 }

Den vigtige del :bemærk, at helt nederst i funktionen videregiver vi til .reduce() vi sørger for at return acc værdi efter vi har ændret det. Dette er påkrævet . Sådan er .reduce() opdaterer værdien af ​​acc efter at vi har ændret det.

Det er det! For hver iteration af vores loop ændrer vi nu acc gemmer det endelige resultat i variablen cart . I bunden af ​​vores fil, lad os tilføje en console.log(cart) så vi kan se outputtet, når vi kører vores kode.

For at køre det, i en terminal fra roden af ​​vores projektmappe, hvis vi kører node index.js vi skulle se noget som dette log ud:

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

Afslutning

I dette selvstudie lærte vi, hvordan man bruger Array.reduce() metode i JavaScript til at konvertere en række objekter til et enkelt objekt. For at demonstrere brugen har vi lavet en fiktiv vogn med items og bruges reducere til at beregne totalen for hver vare sammen med dens afgiftssats.