Att förstå den Allsmäktige Reducer

0
11

Jag var nyligen mentorskap någon som haft problem med den .minska () – metoden i JavaScript. Nämligen, hur du får från detta:

const nums = [1, 2, 3]
låt värde = 0

för (låt i = 0; i < nums.längd; i++) {
value += nums[jag]
}

…till det här:

const nums = [1, 2, 3]
const värde = nums.minska((ac, next) => ac + nästa, 0)

De är funktionellt likvärdiga och de båda sammanfattar alla nummer i rad, men det är lite av ett paradigmskifte mellan dem. Låt oss utforska reducerare för ett ögonblick, eftersom de är kraftfull, och viktigt att ha i din programmering verktygslåda. Det finns bokstavligen hundratals andra artiklar på reduceringar ut det, och jag kommer att länka upp några av mina favoriter på slutet.

Vad är en reducering?

Den första och viktigaste att förstå om en reducering är att det kommer alltid att bara returnera ett värde. Jobbet av en reducering är att minska. Att ett värde kan vara ett tal, en sträng, ett fält eller ett objekt, men det kommer alltid bara finnas en. Reducer är riktigt bra för en massa saker, men de är särskilt användbart för att tillämpa en bit av logik för att en grupp av värden och slutar upp med ett enda resultat.

Det är en annan sak att nämna att de reduceringar som inte kommer till sin natur, mutera din ursprungliga värdet, snarare är de tillbaka med något annat. Låt oss gå över som första exempel så kan du se vad som händer här. Videon nedan förklarar:

Din webbläsare har inte stöd för video-taggen.

Det kan vara bra att titta på videon för att se hur den utvecklingen sker, men här är den kod vi tittar på:

const nums = [1, 2, 3]
låt värde = 0

för (låt i = 0; i < nums.längd; i++) {
value += nums[jag]
}

Vi har vår array (1, 2, 3) och den första att värdera varje rad i matrisen kommer att läggas till (0). Vi går genom mängden av utbud och lägga till dem till det ursprungliga värdet.

Låt oss försöka detta på ett lite annorlunda sätt:

const nums = [1, 2, 3]
const initialValue = 0

const reducer = function (acc, item) {
tillbaka acc + punkt
}

const totalt = nums.minska(reducering, initialValue)

Nu har vi samma rad, men den här gången vi är inte muterar som första värde. I stället har vi en initialValue som endast kommer att användas vid start. Nästa, vi kan göra en funktion som tar en ackumulatortank och ett objekt. Ackumulatorn är den samlade värde returneras i sista instans som informerar funktion vad nästa värde kommer att läggas till. I det här fallet kan man dessutom tänka på det som en snöboll i rullning nedför ett berg som äter upp varje värde i sin väg när det växer i storlek genom att varje ätit värde.

Vi kommer att använda .minska() för att tillämpa funktion och utgå från den ursprungliga värdet. Detta kan kortas av med en pil funktion:

const nums = [1, 2, 3]
const initialValue = 0

const reducer = (acc, artikel) => {
tillbaka acc + punkt
}

const totalt = nums.minska(reducering, initialValue)

Och förkortas lite mer! Implicit avkastning för att vinna!

const nums = [1, 2, 3]
const initialValue = 0

const reducer = (acc, artikel) => acc + punkt

const totalt = nums.minska(reducering, initialValue)

Nu kan vi tillämpa den funktion just där vi kallade det, och vi kan också plopp som första värde direkt i det!

const nums = [1, 2, 3]

const totalt = nums.minska((acc, artikel) => acc + punkt,

En ackumulatortank kan vara en skrämmande sikt, så att du kan se det som att det aktuella läget i den array som vi tillämpar logiken på återuppringning: s instanser.

Call Stack

I fall det inte är klart vad som händer, låt oss logga ut vad som händer för varje iteration. Minska använder sig av en callback-funktion som kommer att köras för varje objekt i arrayen. IThe följande demo kommer att hjälpa till att göra detta mer tydligt. Jag har också använt en annan array ([1, 3, 6]) på grund av att siffrorna vara samma som index kan vara förvirrande.

Se Pennan som visar acc, objekt, avkastning av Sarah Drasner (@sdras) på CodePen.

När vi kör den här, vi får se denna utgång i konsolen:

“Acc: 0, Punkt: 1, returvärde: 1”
“Acc: 1, Punkt: 3, returvärde: 4”
“Acc-n: 4, Punkt: 6, returvärde: 10”

Här är en mer visuell uppdelning:

Din webbläsare har inte stöd för video-taggen.

  1. Det visar att ackumulatortanken är början på vår ursprungliga värdet, 0
  2. Sedan har vi den första punkten, som är 1, så vår avkastning värde är 1 (0 + 1 = 1)
  3. 1 blir det matchstart på nästa anrop
  4. Nu har vi 1 som en ackumulator och 3 är objektet aince det är nästa i kedjan.
  5. Det returnerade värdet blir 4 (1 + 3 = 4)
  6. Det, i sin tur, blir ackumulator och nästa punkt på åkallan är 6
  7. Som resulterar i 10 (4 + 6 = 10) och är vårt slutliga värde eftersom 6 är den sista numret i rad

Enkelt Exempel

Nu när vi har fått det under vår bälte, låt oss titta på några vanliga och användbara saker reduceringar kan göra.

Hur många av X har vi?

Låt oss säga att du har en rad siffror och du vill returnera ett objekt som rapporterar antalet gånger dessa siffror förekommer i matrisen. Observera att detta kunde lika väl gälla strängar.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82]

const resultat = nums.minska((stämmer, amt) => {
stämmer[amt] ? stämmer[amt]++ : stämmer[amt] = 1
avkastning stämmer
}, {})

konsolen.log(resultat)

Se Pennan förenklad minska med Sarah Drasner (@sdras) på CodePen.

Vänta, vad gjorde vi bara göra?

I början, vi har en array och de objekt vi kommer att sätta dess innehåll till. I våra reducering, vi fråga: gör det här objektet finns? Om så är fallet, låt oss öka det. Om inte, lägg till det och sätt det till 1. I slutet, var vänlig och returnera det stämmer räkna på varje punkt. Då vi kör minska funktion, som går i både reducering och det ursprungliga värdet.

Ta en array och förvandla det till ett objekt som visar på några villkor

Låt säga att vi har en array och vi vill skapa ett objekt baserat på en uppsättning av villkor. Minska kan vara bra för detta! Här vill vi skapa ett objekt av någon instans av ett nummer som ingår i kedjan och visa både en udda och jämna versionen av detta nummer. Om numret redan är jämnt eller udda, då det är vad vi ska ha i objektet.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82]

// vi kommer att göra ett objekt från en jämn och udda
// en version av varje instans av en rad
const resultat = nums.minska((acc, artikel) => {
acc[punkt] = {
odd: item % 2 ? artikel : artikel – 1,
även: item % 2 ? post + 1 : punkt
}
tillbaka acc
}, {})

konsolen.log(resultat)

Se Pennan förenklad minska med Sarah Drasner (@sdras) på CodePen.

Detta kommer att skjuta ut följande utdata i konsolen:

1:{udda: 1, även: 2}
3:{udda: 3, även: 4}
4:{udda: 3, även: 4}
5:{udda: 5, även: 6}
6:{udda: 5, även: 6}
82:{udda: 81 även: 82}

OK, så vad är det som händer?

I och med att vi går igenom varje punkt i matrisen, kan vi skapa en fastighet för jämna och udda, och baserat på en infogad skick med en modul som är operatör, vi kommer antingen att lagra numret eller öka den med 1. Den modul som operatör är riktigt bra för detta, eftersom det snabbt kan kontrollera för jämn eller udda — om det är delbart med två, men det är ännu, om inte, det är konstigt.

Andra resurser

På toppen, som jag nämnde andra inlägg där ute som är praktiska resurser för att få mer bekant med den roll reduktionsväxlar. Här är några av mina favoriter:

  • Den MDN dokumentation är underbart för detta. Allvarligt, det är en av deras bästa inlägg, IMO. De har också beskriva lite mer i detalj vad som händer om du inte ger ett startvärde, som vi täckte inte i detta inlägg.
  • Daniel Shiffman är alltid fantastiska på att förklara saker på Kodning Tåg.
  • En Upptining av JavaScript gör ett bra jobb också.

Jetpack WordPress plugin som körs på denna webbplats, driver inte bara relaterade inlägg nedan, men säkerhet och backup, Wiki-stöd, sök på sajten, kommentera form, sociala nätverk, och mycket mer!