Startseite / Artikel

Vier eingebaute JavaScript-APIs, die gängige Lodash-Hilfsfunktionen ersetzen

Wie Math.sumPrecise, Map.getOrInsert, Array.fromAsync sowie Iterator-Hilfsfunktionen die Lodash-Utilities ersetzen, und welche Einschränkungen hinsichtlich Präzision und Konkurrenz man kennen sollte.

Verlag: REACTAPP.TOP4 Min. Lesezeit888 Wörter

Quellen: The 4 ES2026 Features That Finally Replace Lodash

Früher war die Installation von Lodash einer der ersten Schritte in jedem JavaScript-Projekt: Es fügte Zahlen zusammen, füllte Objekte mit Standardwerten und ermöglichte verschachtelte, verzögerte Transformationen. In neueren ECMAScript-Versionen sind bereits integrierte Funktionen für diese Aufgaben enthalten, wodurch die Abhängigkeit oft nur zu einem zusätzlichen Paketgewicht führt. Im Folgenden werden vier eingebettete APIs vorgestellt, was sie ersetzen und wo die übliche einzeilige Erklärung irreführend ist.

Die Unterstützung dieser neueren Funktionen durch Browser und Node.js wird noch schrittweise eingeführt, daher sollten Sie vor dem Hinzufügen eines Polyfills die Kompatibilitätsdaten für Ihre Versionen überprüfen. Für eine umfassendere Übersicht siehe sieben eingebettete JavaScript-Funktionen, die Abhängigkeiten von Hilfsbibliotheken ersetzen.

Math.sumPrecise() anstelle von _.sum()

Zahlen in JavaScript sind IEEE 754-Doppelkommazahlen, weshalb 0.1 + 0.2 den Wert 0.30000000000000004 ergibt. _.sum() bietet keinen Schutz: Es handelt sich um eine einfache Schleife mit +, wodurch alle Rundungsstufen übernommen werden. Math.sumPrecise() nimmt ein iterierbares Objekt entgegen und gibt die Summe so zurück, als wäre sie genau berechnet worden, wobei am Ende einmal gerundet wird.

// ❌ The Legacy Lodash/Hack Way
const prices = [0.1, 0.2];
const total = _.sum(prices); // Still prone to precision errors without custom logic


// ✅ The ES2026 Native Standard
const exactTotal = Math.sumPrecise([0.1, 0.2]);
console.log(exactTotal); // 0.3 (Perfect precision)

Eine Korrektur zum obigen Kommentar: 0.1 und 0.2 sind bereits vor jeder Addition ungenau, und ihre genaue Summe ergibt 0.30000000000000004; daher gibt Math.sumPrecise([0.1, 0.2]) diesen Wert zurück und nicht 0.3. Was die Methode beseitigt, ist der über mehrere Additionen angesammelte Fehler: Für [1e20, 0.1, -1e20] liefert eine naive Addition 0, während Math.sumPrecise 0.1 zurückgibt. Da es sich nicht um einen Dezimaltyp handelt, gehört Geld weiterhin in Ganzzahlig-Cents oder eine Dezimalbibliothek. Zudem wirft sie bei Nicht-Zahlen einen TypeError aus, anstatt diese zu konvertieren.

Map.prototype.getOrInsert() anstelle von has/set/get

Caches und Gruppierungshilfen folgen einem bekannten Muster: Es wird nach einer Schlüssel gesucht, falls dieser fehlt, ein Standardwert gespeichert und anschließend der Wert wieder ausgelesen. getOrInsert(key, defaultValue) erledigt all das in einem Aufruf – es gibt den bereits vorhandenen Eintrag zurück oder fügt einen neuen ein und gibt den Standardwert zurück.

// ❌ The Legacy Way
const userCache = new Map();

function getUser(id) {
  if (!userCache.has(id)) {
    userCache.set(id, { status: 'pending' });
  }
  return userCache.get(id);
}




// ✅ The ES2026 Native Standard
const userCache = new Map();

function getUser(id) {
  // Checks for the key. If missing, inserts the fallback and returns it instantly.
  return userCache.getOrInsert(id, { status: 'pending' });
}

Beachten Sie, dass das Ersatzobjekt bei jedem Aufruf dennoch erstellt wird, selbst wenn es anschließend verworfen wird. Wenn der Standardwert aufwendig zu erstellen ist, verwenden Sie getOrInsertComputed(key, callback), welcher den Callback nur bei einem Fehlsuchergebnis ausführt. Beide Methoden existieren auch in WeakMap; der Aspekt von Node.js wird in Node.js 26: Temporal, Map upserts und Undici 8 erläutert.

Array.fromAsync() zur Verarbeitung asynchroner Iteratoren

Früher bedeutete das Sammeln eines paginierten API-Clients oder eines lesbaren Streams in ein Array den Einsatz einer manuell geschriebenen for await...of-Schleife, die Werte in einen Akkumulator schob. Array.fromAsync() verarbeitet ein asynchron iterierbares Objekt, wartet auf jeden Eintrag und gibt schließlich ein normales Array zurück.

// The ES2026 Native Standard
async function fetchAllPages(asyncPaginationStream) {
  // Consumes the entire async stream and resolves into a flat array
  const allRecords = await Array.fromAsync(asyncPaginationStream);

  return allRecords;
}

Ein optionaler zweiter Parameter wandelt jeden Eintrag um und wartet ebenfalls auf das Ergebnis, wodurch der asynchrone map-Fall abgedeckt wird. Beachten Sie, dass die Einträge sequenziell und in der richtigen Reihenfolge abgewartet werden. Das eignet sich für Streams und Cursor, ersetzt aber Promise.all nicht: Wenn Sie unabhängige Promises haben, die gleichzeitig ausgeführt werden sollen, bleibt Promise.all das richtige Werkzeug. Zudem führt das Buffern eines unbegrenzten Streams im Speicher dazu, dass der Zweck des Streamings untergraben wird.

Iterator-Hilfsfunktionen anstelle von _.chain()

Der stärkste Grund, Lodash beizubehalten, war _.chain(), dessen verzögerte Auswertung es ermöglicht, dass Operationen wie map, filter und take-five an mehr als 10.000 Elementen bereits abbrechen, sobald fünf Ergebnisse vorliegen. Array-Methoden hingegen arbeiten sofort: .map() erstellt ein vollständiges Zwischenarray, .filter() durchläuft dieses erneut und .slice() vernachlässigt anschließend den größten Teil der Arbeit.

Iterator-Hilfsfunktionen, die in ES2025 standardisiert wurden, machen diese verzögerte Auswertung nativ möglich. .values() gibt einen Iterator zurück, und map, filter sowie take ziehen nacheinander ein Element ab, bis toArray() das Ergebnis sammelt.

// ❌ The Array Way (Inefficient: Maps and filters all 10,000 items)
const result = massiveArray
  .map(x => heavyComputation(x))
  .filter(x => x > 100)
  .slice(0, 5);



// ✅ The ES2026 Native Lazy Standard
const result = massiveArray
  .values() // Converts to an Iterator
  .map(x => heavyComputation(x))
  .filter(x => x > 100)
  .take(5) // Stops exactly when 5 items are found!
  .toArray();

Jedes Element durchläuft den gesamten Pipeline-Prozess, bevor das nächste angefordert wird, sodass heavyComputation nur so lange ausgeführt wird, bis fünf Übereinstimmungen gefunden wurden. Kompromisse: Iteratoren sind einmalig verwendbar, es gibt keine verzögerte sort- oder reverse-Funktion, und bei kleinen Arrays sind eifrige Methoden genauso schnell und leichter zu debuggen.

Hauptergebnisse

  • Math.sumPrecise() beseitigt angesammelte Rundungsfehler, kann aber ungenaue Eingaben nicht korrigieren; verwenden Sie für Währungen Ganzzahliges in Cent.
  • getOrInsert() ersetzt has/set/get; wählen Sie getOrInsertComputed(), wenn teure Standardwerte verwendet werden.
  • Array.fromAsync() verarbeitet asynchrone Iterierbare sequenziell; verwenden Sie Promise.all für Konkurrenz.
  • .values() zusammen mit Iterator-Hilfsfunktionen erzeugt verzögerte Pipelines, die _.chain() ähneln, ohne Abhängigkeiten.