JavaScript >> Javascript-Tutorial >  >> Tags >> map

So verwenden Sie Map, um ein Array in JavaScript dynamisch zu ändern

So verwenden Sie die .map()-Methode in JavaScript, um ein Array von Objekten dynamisch zu ändern.

Erste Schritte

Da der Code, den wir für dieses Tutorial schreiben, „eigenständig“ ist (d. h. nicht Teil einer größeren App oder eines größeren Projekts ist), erstellen wir ein Node.js-Projekt von Grund auf neu. Wenn Sie Node.js noch nicht auf Ihrem Computer installiert haben, lesen Sie zuerst dieses Tutorial und kehren Sie dann hierher zurück.

Sobald Sie Node.js auf Ihrem Computer installiert haben, können Sie aus Ihrem Projektordner auf Ihrem Computer (z. B. ~/projects ), erstellen Sie einen neuen Ordner für unsere Arbeit:

Terminal

mkdir map

Als nächstes cd in dieses Verzeichnis und erstellen Sie eine index.js Datei (hier schreiben wir unseren Code für das Tutorial):

Terminal

cd map && touch index.js

Führen Sie als Nächstes im selben Ordner npm init -f aus um einen package.json zu bootstrappen Datei:

Terminal

npm init -f

Dadurch wird NPM (Node Package Manager) angewiesen, einen neuen package.json zu erstellen Datei in Ihrer App. Die -f part steht für "force" und überspringt den Schritt-für-Schritt-Assistenten, den Sie sehen, wenn Sie npm init ausführen von selbst (Sie können dies gerne verwenden, um zu verstehen, wie es funktioniert).

Schließlich müssen wir noch zwei Abhängigkeiten installieren:dayjs und currency.js .

Terminal

npm i dayjs currency.js

Wir verwenden diese beiden, um unsere Daten im Rahmen unseres .map() zu analysieren und zu formatieren .

Damit können wir loslegen.

Benutzerdaten hinzufügen

Unser Ziel für dieses Tutorial ist die Verwendung von Array.map() -Methode in JavaScript, um einige Benutzerdaten zu formatieren und uns dabei zu helfen, zu verstehen, wer unsere wertvollsten Benutzer sind. Lassen Sie uns zunächst einige Testdaten in einer separaten Datei im Stammverzeichnis unseres Projekts hinzufügen:

/users.js

export default [
  {
    "createdAt": "2021-12-08T16:20:14+00:00",
    "invoices": [
      {
        "createdAt": "2021-12-08T16:20:14+00:00",
        "amount": 790.31
      },
      {
        "createdAt": "2021-12-07T16:20:14+00:00",
        "amount": 893.38
      },
      {
        "createdAt": "2021-12-06T16:20:14+00:00",
        "amount": 302.97
      },
      ...
    ],
    "name": {
      "first": "Wester",
      "last": "Christian"
    },
    "emailAddress": "[email protected]"
  },
  ...
];

Hinweis:Dies ist eine verkürzte Liste, da die echte Liste (hier auf Github verfügbar) ziemlich lang ist.

Sobald Sie das in der App haben, können wir mit dem Schreiben unseres .map() fortfahren Funktion über dieses Array.

Zuordnung über das Benutzer-Array

Lassen Sie uns zunächst ein Skelett für unseren .map() erstellen funktionieren und überprüfen und besprechen, wie es funktionieren wird:

/index.js

import users from './users.js';

const spendByUser = users.map((user) => {
  // We'll return our modified user here...
});

console.log(spendByUser);

Zurück in unserem /index.js Datei, hier importieren wir unseren /users.js Datei als users (Denken Sie daran, wir haben einen export default in dieser Datei, sodass wir einfach import users sagen können in unserem Code – wenn dies ein benannter Export wäre, würden wir so etwas wie import { users } from '...' sehen ).

Weil wir wissen, dass users Variable sollte ein Array enthalten (was wir aus /users.js exportiert haben ), können wir .map() aufrufen direkt darauf. Das liegt daran, dass .map() ist eine eingebaute Funktion in JavaScript. Es ist auf Array definiert Prototyp (der Name, der für das Objekt verwendet wird, das die von einer Funktion in JavaScript geerbte Funktionalität enthält). Wir sagen "A" groß Array hier, weil das die Funktion in JavaScript ist, die das Verhalten eines Arrays definiert. Als Teil seines Prototypobjekts haben wir den .map() Funktion (als Methode bekannt, weil es sich um eine Funktion handelt, die für ein vorhandenes Objekt definiert ist).

Wie seine Geschwister .map() ermöglicht es uns, eine Schleife über ein Array auszuführen und etwas zu tun . Das etwas In diesem Fall werden Elemente in einem Array geändert und zurückgegeben, wodurch ein neues Array mit den geänderten Elementen erstellt wird. Ein kurzes Beispiel:

const greetings = ['Hello', 'Goodbye', 'See ya'];

const greetingsWithName = greetings.map((greeting) => {
  return `${greeting}, Ryan!`
});

console.log(greetingsWithName);

// ['Hello, Ryan!', 'Goodbye, Ryan!', 'See ya, Ryan!']

Hier nehmen wir ein Array von Strings und verwenden .map() um dieses Array zu durchlaufen. Für jeden String im Array geben wir einen neuen String zurück (erstellt mit Backticks, damit wir die String-Interpolation von JavaScript nutzen können). Als Gegenleistung zu unserem Aufruf an greetings.map() Wir bekommen ein neues Array. Es ist wichtig zu verstehen :Dies ist ein brandneues, einzigartiges Array. Der .map() Funktion erstellt eine Kopie eines Arrays, das wir .map() nennen Funktion ein und gibt dieses neue Array zurück.

Hier speichern wir das in einer Variablen greetingsWithName und dann console.log() heraus, um die geänderte Kopie zu sehen.

/index.js

import dayjs from 'dayjs';
import users from './users.js';

const spendByUser = users.map((user) => {
  return {
    isLegacyCustomer: dayjs(user?.createdAt).isAfter(dayjs().subtract(60, 'days')),
    name: `${user?.name?.first} ${user?.name?.last}`,
  };
});

console.log(spendByUser);

Jetzt verstehen wir die Grundlagen von .map() , beginnen wir mit der Änderung unseres users Reihe. Genau dieselben Prinzipien sind im Spiel, wie wir oben gesehen haben:Wir nehmen ein Array, rufen .map() auf darauf und erhalten im Gegenzug ein neues Array.

Oben, beachten Sie das über unserem users import haben wir eine der zuvor installierten Abhängigkeiten importiert:dayjs . Unten in unserem .map() Funktion übergeben wir im Callback an .map() , geben wir ein Objekt zurück. Unser Ziel hier ist es, einige "Analysen" für jeden Benutzer durchzuführen und herauszufinden, wie viel jeder Kunde ausgegeben hat und ob es sich um einen Altkunden handelt oder nicht.

Hinweis:Wir müssen nicht genau dieselbe Objektform (oder sogar ein Objekt) von unserem .map() zurückgeben . Wir müssen nur zurückgeben, was immer wir von dem aktuellen Element ersetzen möchten, das wir im Array abbilden.

Hier wollen wir ein neues Objekt erstellen, das drei Eigenschaften hat:

  1. isLegacyCustomer was uns als boolescher true sagt oder false ob der Kunde als Vermächtnis betrachtet wird oder nicht.
  2. name Dies ist die vollständige Namenszeichenfolge des Benutzers/Kunden.
  3. spend das ist der Geldbetrag, den sie bei uns ausgegeben haben, bestehend aus insgesamt ihren invoices Array.

Hier konzentrieren wir uns nur auf isLegacyCustomer und name (spend ist etwas komplizierter, also fügen wir das als nächstes hinzu).

Für isLegacyCustomer , möchten wir wissen, ob der Benutzer vor mehr als 60 Tagen in unserer Datenbank erstellt wurde (wir tun hier nur so). Um das herauszufinden, nehmen wir den createdAt Eigenschaft auf user Objekt und übergeben Sie es an dayjs() (Die Funktion, die wir aus dem gleichnamigen Paket oben importiert haben).

dayjs ist eine Bibliothek zum Manipulieren und Arbeiten mit Datumsangaben. Hier verwenden wir zur Erleichterung unserer Arbeit dayjs() um uns mitzuteilen, ob der Zeitstempel, den wir überschritten haben (user.createdAt ) ist nach ein weiteres Datum, das wir spontan mit einem weiteren Aufruf von dayjs erstellen :dayjs().subtract(60, 'days') . Hier bekommen wir einen dayjs zurück Objekt, das ein Datum vor 60 Tagen enthält.

Als Antwort erwarten wir den .isAfter() Funktion in dayjs um uns einen booleschen true zurückzugeben oder false .

Für name Feld erstellen wir eine Zeichenfolge mit dem gleichen Backtick-Muster, das wir zuvor gesehen haben, diesmal mit Interpolation, um den Vor- und Nachnamen unseres Benutzers zu verketten (miteinander zu verbinden) (unter Verwendung des name.first und name.last Eigenschaften aus dem name Objekt auf den Benutzer).

/index.js

import dayjs from 'dayjs';
import currency from 'currency.js';
import users from './users.js';

const spendByUser = users.map((user) => {
  return {
    isLegacyCustomer: dayjs(user?.createdAt).isAfter(dayjs().subtract(60, 'days')),
    name: `${user?.name?.first} ${user?.name?.last}`,
    spend: user?.invoices?.reduce((total, invoice) => {
      total += invoice.amount;
      return currency(total, { precision: 2 }).value;
    }, 0),
  };
});

console.log(spendByUser);

Jetzt für den kniffligen Teil. Um den spend zu erhalten Eigenschaft für unsere Benutzer, müssen wir eine andere Array-Methode .reduce() verwenden um die user.invoices zu durchlaufen Reihe. Ähnlich einem .map() , die .reduce() Methode durchläuft oder iteriert das Array, für das die Methode aufgerufen wird.

Anstelle eines neuen Arrays wird jedoch ein .reduce() zurückgegeben -Methode gibt den Wert zurück, den wir acc zuweisen oder "Akkumulator". Der Akkumulator in einer Reduce-Funktion ist ein Wert, der mit einem Wert beginnt und – wenn wir .reduce() verwenden für den beabsichtigten Zweck – gibt eine modifizierte oder „aktualisierte“ Version dieses Werts zurück.

Hier beginnt der Akkumulator als 0 als zweites Argument an user?.invoices?.reduce() übergeben (Die Fragezeichen dort sagen nur "Wenn ein Benutzer existiert und Rechnungen darüber existieren, rufen Sie .reduce() an auf user.invoices "). Für jede Schleife oder Iteration von user.invoices , der aktuelle Wert des Akkumulators (wieder beginnend mit diesem 0 ) wird als erstes Argument an die Funktion übergeben, die wir an .reduce() übergeben , hier als total bezeichnet . Als zweites Argument erhalten wir Zugriff auf das aktuelle Element im Array, das durchlaufen wird.

Wenn wir uns hier unseren Code ansehen, ist unser Ziel, die invoice.amount zu "summieren". Feld für jedes Objekt im user.invoices Array.

Für jede Iteration unseres .reduce() , nehmen wir den aktuellen Wert von total und fügen Sie den aktuellen invoice.amount hinzu dazu. Als nächstes nehmen wir das resultierende total und an currency() übergeben Funktion, die wir aus currency.js importiert haben ganz oben in unserer Datei. Dies hilft uns, den Währungswert richtig als Gleitkommazahl zu formatieren (z. B. 123.45 ). An diese Funktion übergeben wir total als erstes Argument und dann ein Optionsobjekt für die Funktion mit precision: 2 als Eigenschaft mit der Aufschrift "Diese Zahl auf zwei Dezimalstellen formatieren."

Abschließend geben wir den .value zurück -Eigenschaft für das Objekt, das durch den Aufruf von currency(total, { precision: 2 }) zurückgegeben wird . Was wir return hier wird der neue oder "aktualisierte" Wert für den Akkumulator, der als total verfügbar sein wird bei der nächsten Schleife/Iteration von user?.invoices . Damit ist es klar, total In unserem Code erhalten Sie hier für jede Iteration mit diesem Beispiel-Array Folgendes (vorausgesetzt, wir beginnen bei 0 ):

[{ amount: 1 }, { amount: 2.55 }, { amount: 3.50 }]

total = 0 // first item
total = 1
total = 3.55
total = 7.05 // last item

Einmal unsere .reduce() abgeschlossen ist, erwarten wir den endgültigen Wert von total (nachdem das letzte Element hinzugefügt wurde) im Gegenzug. Das bedeutet, dass spend sollte insgesamt spend enthalten für jeden unserer Benutzer.

Das ist es! Wenn wir das ausprobieren (stellen Sie sicher, dass Sie sich abmelden spendByUser am Ende unserer Datei), sollten wir etwa Folgendes erhalten:

[
  { isLegacyCustomer: true, name: 'Wester Christian', spend: 10729.91 },
  { isLegacyCustomer: true, name: 'Carthon Weaver', spend: 14926.53 },
  { isLegacyCustomer: true, name: 'Keldrin Durham', spend: 13491.61 },
  { isLegacyCustomer: true, name: 'Jurgen Espinosa', spend: 13179.59 },
  ...
]

Sehen wir uns zum Schluss an, wie Sie diese Daten nutzen können.

Sortierung basierend auf zugeordneten Daten

Warum sollten wir so etwas tun wollen? Wie die meisten Dinge hängt es von unserem Code und dem Projekt ab, an dem wir arbeiten. Um den Kontext hinzuzufügen, könnten wir jedoch davon ausgehen, dass wir versuchen, einen Kunden zu finden, den wir basierend auf seinen Gesamtausgaben bei unserem Unternehmen belohnen. Jetzt, wo wir unser gemapptes Array zur Hand haben, können wir so etwas tun:

/index.js

import dayjs from 'dayjs';
import currency from 'currency.js';
import users from './users.js';

const spendByUser = users.map((user) => { ... });

const mostValuableCustomer = spendByUser.sort((a, b) => a.spend - b.spend).pop();
console.log({ mostValuableCustomer });

Hier haben wir zwei Zeilen hinzugefügt. Wir haben eine Variable mostValueCustomer erstellt und darauf setzen wir das Ergebnis des Aufrufs von .sort() Methode (ein weiterer Array Prototyp-Methode) und ihr eine Funktion übergeben. Diese Funktion nimmt das aktuelle Element und das nächste Element im Array und vergleicht sie, um herauszufinden, welches zuerst kommen sollte. Hier sortieren wir nach den Gesamtausgaben, um zu sagen:"Beginnen Sie mit den geringsten Ausgaben oben und enden Sie mit den höchsten Ausgaben unten."

Mit diesem Ergebnis (wir erwarten, die sortierte Kopie unserer spendByUser zurück zu bekommen array), nennen wir .pop() Methode, um zu sagen:"Legen Sie das letzte Element im Array ab und geben Sie es zurück." Hier der letzte Artikel (der Kunde mit dem höchsten spend ) wird im mostValuableCustomer gespeichert Variable. Wenn wir diese Variable ausloggen, sollten wir Folgendes erhalten, wenn wir unseren Code ausführen:

{ mostValuableCustomer: { isLegacyCustomer: false, name: 'Vicente Henry', spend: 15755.03 } }

Abschluss

In diesem Tutorial haben wir gelernt, wie man Array.map verwendet -Methode, um ein vorhandenes Array zu durchlaufen und seinen Inhalt zu ändern. Wir haben auch gelernt, wie man Daten als Teil dieses .map() formatiert sowie wie die resultierenden Daten in unserem Code verwendet werden.