Masz tablicę użytkowników i potrzebujesz znaleźć konto o konkretnym identyfikatorze. W JavaScript najczęściej użyjesz do tego metody find(), ale wynik zależy od tego, czy szukasz jednego elementu, jego pozycji czy tylko potwierdzenia, że pasuje.
find() zwraca pierwszy pasujący element albo undefined
- Jeden element: użyj
find()z funkcją sprawdzającą warunek. - Wszystkie dopasowania: wybierz
filter(). - Pozycja elementu: użyj
findIndex(), które zwraca-1, gdy niczego nie znajdzie. - Sama odpowiedź tak lub nie: zastosuj
some()alboincludes(), zależnie od rodzaju wyszukiwania. - Pułapka: znaleziony element może mieć wartość
0,falselub pusty tekst, więc nie sprawdzaj wyniku przez prosty warunek prawdziwości.
find() kończy szukanie na pierwszym pasującym elemencie
Wyobraź sobie listę zgłoszeń, w której kilka osób ma status „oczekujące”. Jeśli potrzebujesz obsłużyć pierwsze takie zgłoszenie, find() zwróci sam element, a nie nową tablicę. Właśnie na tym polega jego praktyczna przewaga.
const tickets = [
{ id: 31, status: "closed" },
{ id: 32, status: "pending" },
{ id: 33, status: "pending" }
];
const ticket = tickets.find(item => item.status === "pending");
console.log(ticket);
// { id: 32, status: "pending" }Funkcja przekazana do find() to predykat, czyli warunek zwracający wartość prawdziwą lub fałszywą dla każdego elementu. Metoda sprawdza elementy po kolei i zatrzymuje się przy pierwszym dopasowaniu. Uważam, że nazwa tej metody dobrze pasuje do jej zastosowania: ma znaleźć jeden wynik, a nie budować kolejną kolekcję.
Jeśli nic nie spełni warunku, otrzymasz undefined. To ważne, bo próba odczytania właściwości z takiego wyniku, na przykład ticket.id, zakończy się błędem. Najpierw obsłuż brak dopasowania, a dopiero później korzystaj z właściwości obiektu.
Dobierz metodę do tego, czego potrzebujesz z wyniku
Jedno podobne zapytanie może wymagać zupełnie innej odpowiedzi. Potrzebujesz rekordu, indeksu, listy czy wartości logicznej? Ten wybór przesądza, czy przyda się find(), czy inna metoda tablicy.
| Potrzeba | Metoda | Co zwraca |
|---|---|---|
| Pierwszy element spełniający warunek | find() |
Element albo undefined |
| Wszystkie elementy spełniające warunek | filter() |
Nową tablicę, także pustą |
| Indeks pierwszego elementu spełniającego warunek | findIndex() |
Indeks albo -1 |
| Informacja, czy dowolny element spełnia warunek | some() |
true albo false |
| Sprawdzenie, czy tablica zawiera dokładną wartość | includes() |
true albo false |
Gdy masz listę cen i chcesz zebrać wszystkie pozycje tańsze od określonego progu, filter() opisuje zamiar lepiej niż find(). Jeśli interesuje cię tylko to, czy istnieje choć jedna taka cena, wybierz some(). Dokumentacja MDN opisuje te metody jako osobne narzędzia do zwracania elementu, indeksu, wszystkich dopasowań albo odpowiedzi logicznej.
Przy pięciu rekordach wynik zależy od kolejności tablicy
Załóżmy, że przeglądasz pięć zgłoszeń, a warunek pasuje do elementów na pozycjach 2 i 5. find() sprawdzi elementy po kolei, zatrzyma się na pozycji 2 i zwróci jeden rekord. Nie sprawdzi ostatniego zgłoszenia, bo wynik jest już rozstrzygnięty.
const ids = [101, 102, 103, 104, 105];
let checks = 0;
const result = ids.find(id => {
checks++;
return id > 101;
});
console.log(result); // 102
console.log(checks); // 2W tym przykładzie wywołania predykatu jest dwa, nie pięć. Jeśli jednak pasujący element znajduje się na końcu albo nie ma dopasowania, metoda może sprawdzić całą tablicę. Dlatego przy powtarzanym wyszukiwaniu w bardzo dużych kolekcjach zwróć uwagę na kolejność danych, ale nie zakładaj z góry konkretnego zysku wydajnościowego: zależy on od położenia wyniku i pracy wykonywanej w predykacie.
Wynik sprawdzaj jawnie, bo dopasowanie może być wartością falsy
Warunek if (result) wygląda naturalnie, lecz może błędnie potraktować znalezione 0, false albo pusty tekst jak brak wyniku. Problem nie tkwi wtedy w wyszukiwaniu. Tkwi w sprawdzeniu tego, co metoda zwróciła.
const values = [0, 4, 7];
const result = values.find(value => value === 0);
if (result !== undefined) {
console.log("Znaleziono:", result);
}Porównanie z undefined rozróżnia brak dopasowania od znalezionego zera. Przy tablicy, która może zawierać samo undefined, wynik find() nie pozwoli odróżnić znalezionej wartości od braku elementu; wtedy użyj findIndex(), który sygnalizuje brak indeksem -1.
| Sytuacja | Możliwy skutek | Co zrobić |
|---|---|---|
Wynik to 0, false lub "" |
Warunek if (result) uzna znalezioną wartość za brak |
Porównaj wynik z undefined |
| Brak elementu spełniającego warunek | Wynik to undefined; odczyt jego właściwości zgłosi błąd |
Obsłuż brak wyniku przed użyciem właściwości |
Tablica może zawierać undefined |
Nie rozpoznasz, czy wartość została znaleziona | Użyj findIndex() i sprawdź, czy indeks jest różny od -1 |
Przekazujesz findIndex() do splice() |
Indeks -1 może wskazać koniec tablicy zamiast braku elementu |
Najpierw sprawdź wynik, dopiero potem usuń element |
Rzadkie tablice i zmiany w predykacie mają mniej oczywiste skutki
Pusta pozycja w rzadkiej tablicy bywa mylona ze zwykłym pominięciem elementu. W przypadku find() callback jest jednak wywoływany także dla takich indeksów, a otrzymaną wartością jest undefined. Jeśli predykat wyszukuje właśnie undefined, pusta pozycja może więc zostać uznana za dopasowanie.
const values = [10, , 30];
const result = values.find(value => value === undefined);
console.log(result); // undefinedTu jest haczyk: taki sam wynik pojawia się, kiedy żadnego elementu nie znaleziono. Przy tablicach z pustymi pozycjami i wartościami undefined sprawdź indeks zamiast polegać wyłącznie na zwróconej wartości. Opis zachowania pustych pozycji znajduje się w dokumentacji metody Array.prototype.find().
Nie zmieniaj też bez potrzeby tablicy w trakcie wykonywania predykatu. Jeżeli logika callbacku usuwa lub podmienia elementy, wynik trudniej przewidzieć i utrzymać. Zwykle czytelniej jest znaleźć element, a zmianę wykonać osobno, korzystając z indeksu, jeśli jest potrzebny.
Najprostsza zasada wyboru oszczędza błędne odczyty
Dobór można sprowadzić do jednego pytania: jaki kształt ma mieć odpowiedź? Jeden obiekt oznacza find(), lista pasujących elementów oznacza filter(), pozycja to findIndex(), a samo „czy istnieje?” prowadzi do some() lub includes().
Gdybym wybierał metodę dla kodu aplikacyjnego, postawiłbym na tę, której nazwa i wynik najwierniej opisują zamiar. Dzięki temu następna osoba czytająca kod od razu widzi, czy oczekiwany jest jeden rekord, cała lista czy tylko odpowiedź logiczna, a obsługa braku dopasowania przestaje być niespodzianką.
