Map, reduce und filter sind drei sehr nützliche Array-Methoden in JavaScript, die Entwicklern viel Macht auf kleinem Raum geben. Springen wir direkt hinein, wie Sie diese super praktischen Methoden nutzen können (und wie Sie sich erinnern, wie man sie benutzt!).
Array.map()
Array.map() aktualisiert jeden einzelnen Wert in einem gegebenen Array basierend auf einer bereitgestellten Transformation und gibt ein neues Array gleicher Größe zurück. Es akzeptiert eine Callback-Funktion als Argument, die es zur Anwendung der Transformation verwendet.
let newArray = oldArray.map((value, index, array) => {
...
});
Ein Merkspruch hierfür ist MAP: Morph Array Piece-by-Piece (Array Stück für Stück formen).
Anstatt einer for-each-Schleife, um diese Transformation auf jeden Wert anzuwenden, können Sie eine Map verwenden. Dies funktioniert, wenn Sie jeden Wert erhalten, ihn aber aktualisieren möchten. Wir eliminieren potenziell keine Werte (wie bei einem Filter) und berechnen keine neue Ausgabe (wie bei Reduce). Eine Map ermöglicht es Ihnen, ein Array Stück für Stück zu formen. Schauen wir uns ein Beispiel an.
[1, 4, 6, 14, 32, 78].map(val => val * 10)
// the result is: [10, 40, 60, 140, 320, 780]
Im obigen Beispiel nehmen wir ein Anfangsarray ([1, 4, 6, 14, 32, 78]) und bilden jeden Wert darin so ab, dass er das Zehnfache des Werts ist (val * 10). Das Ergebnis ist ein neues Array, in dem jeder Wert des ursprünglichen Arrays durch die Gleichung transformiert wurde: [10, 40, 60, 140, 320, 780].

Array.filter()
Array.filter() ist eine sehr praktische Abkürzung, wenn wir ein Array von Werten haben und diese Werte in ein anderes Array filtern möchten, wobei jeder Wert im neuen Array ein Wert ist, der einen bestimmten Test besteht.
Dies funktioniert wie ein Suchfilter. Wir filtern Werte heraus, die die von uns bereitgestellten Parameter bestehen.
Wenn wir zum Beispiel ein Array von numerischen Werten haben und nur die Werte herausfiltern wollen, die größer als 10 sind, könnten wir schreiben
[1, 4, 6, 14, 32, 78].filter(val => val > 10)
// the result is: [14, 32, 78]
Wenn wir eine Map-Methode auf dieses Array anwenden würden, wie im obigen Beispiel, würden wir ein Array derselben Länge wie das Original zurückgeben, wobei val > 10 die „Transformation“ oder in diesem Fall ein Test wäre. Wir transformieren jeden der ursprünglichen Werte in seine Antwort, wenn er größer als 10 ist. Das würde so aussehen
[1, 4, 6, 14, 32, 78].map(val => val > 10)
// the result is: [false, false, false, true, true, true]
Ein Filter gibt jedoch *nur* die wahren Werte zurück. Das Ergebnis ist also kleiner als das ursprüngliche Array oder gleich groß, wenn alle Werte einen bestimmten Test bestehen.
Denken Sie an **filter** wie an einen Sieb-Filter. Ein Teil der Mischung wird durchgelassen, ein Teil bleibt zurück und wird verworfen.

Nehmen wir an, wir haben eine (sehr kleine) Klasse von vier Hunden in einer Hundeschule. Alle Hunde hatten während der Hundeschule Herausforderungen und legten eine benotete Abschlussprüfung ab. Wir stellen die Hunde als Array von Objekten dar, d.h.
const students = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Kitten",
finalGrade: 45
},
{
name: "Taco",
finalGrade: 100
},
{
name: "Lucy",
finalGrade: 60
}
]
Wenn die Hunde eine Punktzahl über 70 in ihrem Abschlusstest erreichen, erhalten sie ein schickes Zertifikat; wenn nicht, müssen sie den Kurs wiederholen. Um zu wissen, wie viele Zertifikate gedruckt werden müssen, müssen wir eine Methode schreiben, die die Hunde mit bestandenen Noten zurückgibt. Anstatt eine Schleife zu schreiben, um jedes Objekt im Array zu testen, können wir unseren Code mit filter kürzen!
const passingDogs = students.filter((student) => {
return student.finalGrade >= 70
})
/*
passingDogs = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Taco",
finalGrade: 100
}
]
*/
Wie Sie sehen können, sind Boops und Taco gute Hunde (eigentlich sind alle Hunde gute Hunde), also bekommen Boops und Taco Leistungszertifikate für das Bestehen des Kurses! Wir können dies mit unseren schönen impliziten Rückgaben in einer einzigen Codezeile schreiben und dann die Klammern von unserer Pfeilfunktion entfernen, da wir ein einzelnes Argument haben.
const passingDogs = students.filter(student => student.finalGrade >= 70)
/*
passingDogs = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Taco",
finalGrade: 100
}
]
*/
Array.reduce()
Die Methode reduce() nimmt die Eingabewerte eines Arrays und gibt einen einzelnen Wert zurück. Diese ist wirklich interessant. Reduce akzeptiert eine Callback-Funktion, die aus einem Akkumulator (ein Wert, der jedes Stück des Arrays sammelt, wie ein Schneeball wächst), dem Wert selbst und dem Index besteht. Sie nimmt auch einen Startwert als zweites Argument an.
let finalVal = oldArray.reduce((accumulator, currentValue, currentIndex, array) => {
...
}), initalValue;

Lassen Sie uns eine Kochfunktion und eine Liste von Zutaten aufstellen.
// our list of ingredients in an array
const ingredients = ['wine', 'tomato', 'onion', 'mushroom']
// a cooking function
const cook = (ingredient) => {
return `cooked ${ingredient}`
}
Wenn wir die Zutaten zu einer Sauce reduzieren wollen (Wortspiel absolut beabsichtigt), reduzieren wir sie mit reduce()!
const wineReduction = ingredients.reduce((sauce, item) => {
return sauce += cook(item) + ', '
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom, "
Dieser Anfangswert (in unserem Fall '') ist wichtig, denn wenn wir ihn nicht haben, kochen wir das erste Element nicht. Das macht unsere Ausgabe etwas seltsam, also ist es definitiv etwas, worauf man achten sollte. Hier ist, was ich meine.
const wineReduction = ingredients.reduce((sauce, item) => {
return sauce += cook(item) + ', '
})
// wineReduction = "winecooked tomato, cooked onion, cooked mushroom, "
Um sicherzustellen, dass wir am Ende unserer neuen Zeichenkette keine überschüssigen Leerzeichen haben, können wir den Index und das Array übergeben, um unsere Transformation anzuwenden.
const wineReduction = ingredients.reduce((sauce, item, index, array) => {
sauce += cook(item)
if (index < array.length - 1) {
sauce += ', '
}
return sauce
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"
Jetzt können wir dies noch prägnanter (in einer einzigen Zeile!) schreiben, indem wir ternäre Operatoren, Zeichenfolgen-Vorlagen und implizite Rückgaben verwenden.
const wineReduction = ingredients.reduce((sauce, item, index, array) => {
return (index < array.length - 1) ? sauce += `${cook(item)}, ` : sauce += `${cook(item)}`
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"
Eine kleine Eselsbrücke, um sich dies zu merken, ist, sich daran zu erinnern, wie man Sauce macht: Man **reduziert** ein paar Zutaten zu einem einzigen Gegenstand.
Sing it with me! (Singen Sie mit mir!)
Ich wollte diesen Blogbeitrag mit einem Lied beenden, also habe ich ein kleines Liedchen über Array-Methoden geschrieben, das Ihnen vielleicht helfen könnte, sich diese zu merken.
Und natürlich hinterlasse ich einen Kommentar mit Code, der nicht funktioniert (Backseat Coding!). Das hätte sein sollen...
const wineReduction = ingredients.reduce((sauce, item) => ([sauce, cook(item)].filter(x => x).join(', ')), '');
Das war großartig! Danke, dass Sie ein so kreativer Mensch sind! :D
Coole Erklärungen!
Ich möchte jedoch auf eine potenzielle Fallstrick bei reduce hinweisen. In der Lambda haben Sie geschrieben
return sauce += cook(item) + ‘, ‘
Es ist jedoch nicht notwendig, hier += zu verwenden, da der nächste Aufruf der Lambda nicht dieselbe Sauce verwendet, sondern den Rückgabewert als seine Sauce verwendet.
Die Verwendung von + reicht aus. += ist auch sehr weit vom funktionalen Stil von map/filter/reduce entfernt, da es sauce mutiert (auch wenn es nur eine lokale Variable ist).
Für die zweite Version, in der wir die Prüfung auf das Komma haben, könnten wir die temporäre neue Sauce in einer neuen Variablen speichern, z. B.
const nextSauce = sauce + cook(item);
Ich liebe den Artikel und das Lied. Ich werde die 3 jetzt benutzen.
Das ist großartig!
Kann ich eine kleine Korrektur im ersten
reduce-Beispiel beisteuern.Das zweite Argument befindet sich außerhalb der Klammern, es sollte sein
Sehr gut erklärt und das Lied gefällt mir auch :) Danke
Erstaunlich! Danke
Jetzt verstehe ich die Methoden Array.map() und Array.filter() klar. Ich werde die .reduce()-Methode noch einmal durchgehen.
Sehr schöner Artikel. Diese drei Funktionen (Methoden) sind sehr nützlich und es wäre toll, wenn mehr Leute davon wüssten.
Ein Vorschlag jedoch; Sie können Ihr erstes reduce-Beispiel ziemlich stark vereinfachen, zu nur
ingredients.reduce((sauce, ingredient) => sauce + ‘, ‘ + ingredient)
Dies fügt keine Komma vor dem ersten Argument hinzu, da es die Funktion für das erste Argument überhaupt nicht aufruft, sondern mit dem zweiten beginnt und das erste als Akkumulator übergibt.
Ja, das habe ich mir auch gedacht!;)
Schöner Artikel und Song! Aber das reduce-Beispiel schien mir überkompliziert, es ist einfacher, das getrennte gekochte Essen mit Kommas zu erhalten, indem man
join(", ")verwendet.Toller Artikel, aber ich denke, Sie haben ein wichtiges Detail von
reduce()überflogen: Wenn der ParameterinitialValuenicht angegeben ist, wird standardmäßig das erste Element des Quellarrays verwendet. Sie haben dies in Ihrem Ausgabekommentar gezeigt, aber nicht genau erklärt (Sie sagten nur, es würde die Ausgabe „seltsam“ machen).Das war wirklich gut erklärt, danke. Ich bin im Reduce-Teil verloren gegangen, aber die .map und .filter haben sie so viel einfacher gemacht, als sie mir bisher erklärt wurden.
Wirklich schöne Präsentation, aber ein paar Dinge.
1) Ihre Formulierung bei map lässt es so klingen, als würde das ursprüngliche Array mutiert werden, aber das ist nicht der Fall.
2) Ihr anfänglicher Codeausschnitt für reduce ist falsch. Ihr Anfangswert sollte sich innerhalb der Klammern befinden.
let finalVal = oldArray.reduce((accumulator, currentValue, currentIndex, array) => {
…
}, initialValue);
Andere kleinere Probleme wurden bereits von Aron erwähnt.
Außerdem ist zu beachten, dass
returnoptional ist.const cook = (ingredient) => {return
cooked ${ingredient}};könnte sein
const cook = (ingredient) =>
cooked ${ingredient};ROFL…
Sie sind verrückt! Im sehr positiven Sinne :-)