Strona główna / Artykuły

Cztery wbudowane API JavaScript, które zastępują popularne narzędzia Lodash

W jaki sposób Math.sumPrecise, Map getOrInsert, Array.fromAsync oraz narzędzia pomocnicze typu iterator zastępują funkcje z Lodash, oraz jakie są kwestie związane z dokładnością i równoczesnością, które należy znać.

Wydawca: REACTAPP.TOP4 min czytania888 słów

Źródła: The 4 ES2026 Features That Finally Replace Lodash

Instalowanie Lodash było kiedyś jednym z pierwszych kroków w każdym projekcie JavaScript: sumowało liczby, wypełniało tablice wartościami domyślnymi oraz łączyło opóźnione transformacje. Nowsze wersje ECMAScript zawierają wbudowane odpowiedniki tych funkcji, więc ta zależność często stanowi jedynie dodatkową wagę pliku. Poniżej przedstawiono cztery natywne API, to, co zastępują, oraz sytuacje, w których typowe jednozdaniowe wyjaśnienia są mylące.

Wsparcie silników dla tych nowszych dodatków jest nadal wdrażane, dlatego przed zastosowaniem polyfilla sprawdź dane dotyczące kompatybilności swoich przeglądarek i wersji Node.js. Aby uzyskać szerszy przegląd, zapoznaj się z siedmioma natywnymi funkcjami JavaScript, które zastępują zależności od bibliotek pomocniczych.

Math.sumPrecise() zamiast _.sum()

Liczby w JavaScript to liczby podwójne według standardu IEEE 754, dlatego 0.1 + 0.2 daje 0.30000000000000004. Funkcja _.sum() nie zapewnia żadnej ochrony: jest to zwykły pętla operacji +, więc przechowuje wszystkie efekty zaokrągleń. Funkcja Math.sumPrecise() przyjmuje obiekt iterowalny i zwraca sumę tak, jakby została obliczona dokładnie, zaokrąglając ją tylko raz na końcu.

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

Jedna korekta do powyższego komentarza: 0.1 i 0.2 są już nieprecyzyjne przed jakimkolwiek dodawaniem, a ich dokładna suma po zaokrągleniu daje 0.30000000000000004, więc Math.sumPrecise([0.1, 0.2]) zwraca tę wartość, a nie 0.3. Metoda ta usuwa błędy nagromadzone podczas wielu dodawania: dla [1e20, 0.1, -1e20] proste dodawanie daje 0, podczas gdy Math.sumPrecise zwraca 0.1. Ponieważ nie jest to typ dziesiętny, pieniądze nadal powinny być przechowywane jako liczby całkowite w centach lub za pomocą biblioteki dziesiętnych liczb. Ponadto metoda rzuca błąd TypeError w przypadku wartości niebędących liczbami, zamiast je przekształcać.

Map.prototype.getOrInsert() zamiast has/set/get

Pomocniki do cache’owania i grupowania wykazują podobny schemat: sprawdza się klucz, przechowuje wartość domyślną w razie jej braku, a następnie odczytuje wartość z powrotem. getOrInsert(key, defaultValue) robi to wszystko w jednej wywołaniu, zwracając istniejącą pozycję lub wprowadzając i zwracając wartość domyślną.

// ❌ 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' });
}

Należy pamiętać, że obiekt awaryjny jest nadal tworzony przy każdym wywołaniu, nawet gdy zostaje odrzucony. Jeśli wartość domyślna jest kosztowna w obliczeniach, należy użyć getOrInsertComputed(key, callback), który uruchamia funkcję odwołania tylko w przypadku braku klucza. Obie te metody istnieją również w WeakMap; aspekty związane z Node.js omówiono w Node.js 26: Temporal, Map upserts i Undici 8.

Array.fromAsync() do wyczerpywania asynchronicznych iterowalnych obiektów

Zbieranie paginowanego klienta API lub strumienia do możliwości odczytu do tablicy oznaczało kiedyś ręczne użycie pętli for await...of, która wpisywała dane do akumulatora. Funkcja Array.fromAsync() konsumuje asynchroniczny iterowalny obiekt, czeka na każdy element i zwraca zwykłą tablicę.

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

Opcjonalny drugi argument mapuje każdy element, a jego wynik również jest oczekiwany, co obejmuje przypadek asynchronicznego użycia metody map. Należy pamiętać, że elementy są oczekiwane sekwencyjnie, po kolei. To nadaje się do strumieni i kursorów, ale nie zastępuje Promise.all: jeśli masz niezależne obietnice, które powinny działać równocześnie, Promise.all nadal jest odpowiednim narzędziem. Ponadto buforowanie nieskończonego strumienia w pamięci podważa cel pracy z strumieniami.

Pomocniki iteratorów zamiast _.chain()

Najważniejszym powodem, dla którego nadal używamy Lodash, jest metoda _.chain(), której ocena opóźniona umożliwia funkcjom takim jak map, filter i take-five przetwarzanie ponad 10 000 elementów, zatrzymując się po uzyskaniu pięciu wyników. Metody tablic są natychmiastowe: .map() tworzy pełną tablicę pośrednią, .filter() przegląda ją ponownie, a .slice() odrzuca większość wykonywanych operacji.

Pomocniki iteratorów, ustandaryzowane w ES2025, umożliwiają takie przetwarzanie opóźnione w sposób natywny. Metoda .values() zwraca iterator, a metody map, filter i take na nim pobierają po jednym elemencie, aż metoda toArray() zebrze wszystkie wyniki.

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

Każdy element przechodzi przez cały proces przed tym, jak zostanie zażądany następny, więc heavyComputation jest wykonywany tylko do momentu znalezienia pięciu dopasowań. Kompromisy: iteratorzy służą do jednorazowego użycia, nie ma opcji opóźnionego sortowania lub odwracania, a w przypadku małych tablic metody natychmiastowe są równie szybkie i łatwiejsze do debugowania.

Główne wnioski

  • Math.sumPrecise() usuwa nagromadzoną błąd zaokrąglenia, ale nie może naprawić niedokładnych danych wejściowych; do reprezentacji walut należy używać całkowitych wartości w centach.
  • getOrInsert() zastępuje funkcje has/set/get; w przypadku drogich domyślnych wartości lepiej użyć getOrInsertComputed().
  • Array.fromAsync() przetwarza asynchroniczne iterowalne obiekty sekwencyjnie; do obsługi równoległości należy używać Promise.all.
  • .values() w połączeniu z pomocnikami iteratorów umożliwia tworzenie opóźnionych procesów przetwarzania podobnych do _.chain() bez konieczności używania dodatkowych zależności.

Powiązane materiały