Uwaga! Trwają prace nad nową wersją serwisu. Mogą występować przejściowe problemy z jego funkcjonowaniem. Przepraszam za niedogodności!

⛔ Potrzebujesz wsparcia? Oceny CV? A może Code Review? ✅ Dołącz do naszej społeczności na Discordzie!

Metody tablicowe JavaScript – powtórka przed Reactem

Działanie metod JS i przykłady użycia

Framework czy biblioteka JS jak React to kolejny krok podczas nauki programowania. Warto zrobić go, mając usystematyzowane podstawy. Zobacz, jakich metod JavaScript często używa się podczas pracy z Reactem (choć nie tylko) i jak pomagają one w operowaniu na danych. W artykule znajdziesz wyjaśnienie działania pięciu popularnych metod tablicowych oraz przykłady ich zastosowania.

Chcesz lepiej zapamiętać to zagadnienie? Wykonaj warsztat z JavaScript: Podstawy, aby osiągnąć swój cel!

Spis treści

 Metoda map()

Metoda map() w JavaScript służy do iteracji po elementach tablicy i przekształcania ich w nowe elementy na podstawie określonej funkcji (callbacku). Funkcję tę przekazujemy do metody jako argument.

Tak utworzone elementy trafiają do nowej tablicy, którą metoda map() zwraca.

 Jak działa map()

Iteracja i przekształcanie

Metoda map() przechodzi przez każdy element tablicy i wykonuje na nim operacje określone w callbacku, przekształcając go w nowy element.

Trzy parametry w callbacku – element, numer indeksu i tablica

Warto pamiętać, że callback może korzystać nie tylko z elementów tablicy, ale też z ich numerów indeksów oraz samej przetwarzanej tablicy:

const numbers = [1, 2, 3, 4, 5];
const multipliedNumbers = numbers.map((element, index, array) => {

// Jeśli tablica ma więcej elementów niż jeden, to…
if (array.length > 1) {

// elementy z indeksami parzystymi pomnóż razy 2, a pozostałe razy 3
return index % 2 === 0 ? element * 2 : element * 3
}
return element // gdyby tablica miała jeden element lub mniej, zwróć tylko ten element
});

console.log(multipliedNumbers) // [2, 6, 6, 12, 10]

To bardzo teoretyczny przykład, lecz zwłaszcza wykorzystanie indeksu może Ci się niejednokrotnie przydać. Zwróć jednak uwagę, że nawiązanie do tablicy poprzez argument array (nazwa jest dowolna) też przynosi korzyści. Gdyby nazwa tablicy numbers uległa zmianie, a użylibyśmy jej wcześniej w ciele callbacku, wówczas trzeba by ją zmieniać w co najmniej dwóch miejscach.

Tworzenie nowej tablicy

Metoda map() zwraca nową tablicę, w której każdy element jest wynikiem przekształcenia odpowiadającego mu elementu z oryginalnej tablicy.

Uwaga: jeśli nie potrzebujesz nowej tablicy, a chcesz jedynie wykonać operacje na elementach aktualnej tablicy, wybierz metodę forEach().

 Przykład użycia map()

Metoda map() jest wykorzystywana w Reakcie niemal na każdym kroku do tworzenia podobnych komponentów różniących się zawartością, np. jak kafelki prezentujące produkty w sklepie internetowym czy lista znajomych na Facebooku (każdy element wygląda podobnie, lecz różni się zawartością). Poniżej widzisz bardzo prosty komponent funkcyjny, który zawiera listę e-booków.

const ProductList = () => {
  const productTitles = ['Ebook1', 'Ebook2', 'Ebook3'];
  
  // Tworzymy tablicę z elementami <li>
  const productItems = productTitles.map((title, index) => (
        <li key={index}>{title}</li>
      ))

  // Wyświetlamy listę produktów
  return (
    <ul>
      {productItems}
    </ul>
  );
};

// Powyższy kod po kompilacji do JS wygląda tak:
<ul>
  <li>Ebook1</li>
  <li>Ebook2</li>
  <li>Ebook3</li>
</ul>

Tytuły książek zamieszczone są w tablicy productTitles. Na jej podstawie tworzymy elementy li przechowywane w zmiennej productItems. Zmienną tę umieszczamy wewnątrz ul i w ten sposób uzyskujemy listę e-booków (nie przejmuj się, jeśli nie rozumiesz jeszcze składni Reacta).

 Metoda forEach()

Metoda forEach() działa niemal tak samo jak metoda map(), dlatego nie będziemy jej szczegółowo omawiać. Dodatkowo do tworzenia czy edytowania komponentów jest wykorzystywana raczej rzadko.

forEach() iteruje po elementach tablicy i wykonuje na nich operacje określone w przekazanym callbacku, ale nic nie zwraca (a dokładniej zwraca undefined). W Reakcie użyjesz jej jak w zwykłym JS-ie – np. do walidacji wartości z formularza.

W callbacku metody forEach() również mamy dostępne trzy parametry: element, numer indeksu i tablicę, po której iterujemy.

Uwaga: mylenie wykorzystania metody map() i forEach() jest dość powszechne u osób początkujących. Jeśli w podglądzie swojego projektu nie widzisz np. tworzonych komponentów, a konsola stale wyświetla Ci undefined, to sprawdź, czy na pewno stosujesz map(), a jeśli tak, to czy zwracasz z tej metody wartość za pomocą return (pamiętaj, że w funkcji strzałkowej, której instrukcja zawiera się w jednej linii, return jest domyślne).

 Przykład użycia forEach()

Wyżej wspomniany został przykład walidacji formularza JS. Dane o polach przechowujemy w tablicy formFields i to na jej podstawie generujemy formularz. Sprawdzenie, czy pola zostały wypełnione, mogłoby wyglądać tak:

const fields = [{
    name: 'firstName',
    label: 'Imię',
    required: true
  },
  {
    name: 'lastName',
    label: 'Nazwisko',
    required: true
  },
  {
    name: 'city',
    label: 'Miasto',
    required: true
  }
];

// (...) – kod odpowiedzialny za generowanie pól formularza w drzewie DOM

const formEl = document.querySelector('form');

// walidacja – sprawdzamy, czy każde z pól zostało wypełnione
fields.forEach(function(field) {
  // wykorzystujemy właściwość obiektu o nazwie name, by pobrać wartość konkretnego elementu formularza
  const value = formEl.elements[field.name].value;
  if (field.required) {
    if (value.length === 0) {
      errors.push('Dane w polu ' + field.label + ' są wymagane.');
    }
  }
})

 Metoda filter()

Metoda filter() w JavaScript służy do filtrowania elementów tablicy na podstawie określonego warunku. Przyjmuje ona funkcję zwrotną (callback), która decyduje, czy dany element spełnia warunek filtrowania.

 Jak działa filter()

Iteracja i sprawdzanie warunku filtrowania

Metoda filter() przechodzi przez każdy element tablicy. Jeśli element ten spełnia warunek podany w callbacku (true), to zostaje on dodany do nowej tablicy. Jeśli nie spełnia warunku (false), zostaje odrzucony.

Trzy parametry w callbacku – element, numer indeksu i tablica

Tak, tutaj callback również może korzystać nie tylko z elementów tablicy, ale i z ich numerów indeksów oraz samej przetwarzanej tablicy.

Tworzenie nowej tablicy

Metoda filter() zwraca nową tablicę. Zawiera ona tylko te elementy, które spełniły warunek filtrowania w callbacku.

 Przykład użycia filter()

W Reakcie komponenty możemy wyświetlać zależnie od akcji użytkownika. Dla przykładu udostępnimy w sklepie filtry do pokazania jedynie produktów z danego przedziału cenowego Zaimplementujemy to właśnie za pomocą metody filter().

// Przykładowa tablica produktów z serwera
const products = [
  { id: 1, name: 'Product 1', price: 10 },
  { id: 2, name: 'Product 2', price: 20 },
  { id: 3, name: 'Product 3', price: 15 },
  { id: 4, name: 'Product 4', price: 25 },
];

// Przykład filtrowania produktów. Uproszczony (zauważ, że ceny są wpisane ręcznie, a nie pobrane od użytkownika)
const filteredByPrice = products.filter((product) => {
  return product.price >= 10 && product.price <= 20;
});

Dzięki metodzie filter() uzyskaliśmy nową tablicę w zmiennej filteredByPrice. Zawiera ona trzy pierwsze produkty, ponieważ tylko one spełniają warunek filtrowania (zakres ceny od 10 do 20).

W Reakcie na jej podstawie dzięki użyciu metody map() wyrenderowalibyśmy odpowiednie komponenty. Po stronie interfejsu użytkownika wyglądałoby to w ten sposób, że po zatwierdzeniu wartości filtra cenowego, wyświetliłyby się produkty numer 1, 2 i 3.

Uwaga: tam, gdzie przeszukujesz tablicę pod kątem jednego elementu spełniającego warunek (np. konkretnego numeru ID), użyj metody bardziej do tego odpowiedniej: find().

 Metoda find()

Metoda find() w JavaScript służy do wyszukiwania w tablicy pierwszego elementu, który spełnia określony warunek. Przyjmuje ona funkcję zwrotną (callback), która decyduje, czy dany element spełnia warunek wyszukiwania.

 Jak działa find()

Iteracja i sprawdzanie warunku wyszukiwania

Metoda find() przechodzi przez każdy element tablicy. Jeśli element ten spełnia warunek podany w callbacku (true), to zostaje on zwrócony. Jeśli żaden element nie spełnia warunku (false), metoda zwraca undefined.

Uwaga: Wartość falsy (czyli np. właśnie undefined) będzie w Reakcie przydatna przy tzw. renderowaniu warunkowym – spójrz na przykład poniżej.

const products = [
  { id: 1, name: 'Product 1', price: 10 },
  { id: 2, name: 'Product 2', price: 20 },
  { id: 3, name: 'Product 3', price: 15 },
  { id: 4, name: 'Product 4', price: 25 },
];

const ProductComponent = () => {
  const product = products.find((prod) => prod.id === 2); // szukamy produktu o ID równym 2

// Jeśli metoda find() zwróci wyszukany element, to zostanie on wyrenderowany; jeśli zwróci undefined, to wyświetli się komunikat
  return (
    <p>{product ? product.name : 'Product not found'}</p>
  );
};

Trzy parametry w callbacku – element, numer indeksu i tablica

Tutaj jak wcześniej: callback może korzystać nie tylko z elementów tablicy, ale i z ich numerów indeksów oraz samej przetwarzanej tablicy.

Wynik wyszukiwania

Metoda find() zwraca albo znaleziony element, albo undefined, jeśli nie znajduje żadnego elementu spełniającego warunek.

 Przykład użycia find()

Używaj find() zawsze tam, gdzie spodziewasz się znalezienia jednego elementu (w przeciwnym razie stosuj metodę filter()).

Poniżej widzisz przykład formularza HTML. Załóżmy, że chcemy sprawdzić poprawność wprowadzonych przez użytkownika danych w polu kodu pocztowego. Pole to ma nadaną przez nas niepowtarzalną nazwę "zip", dzięki czemu możemy wyszukać je metodą find() i sprawdzić, czy wprowadzona wartość pasuje do wyrażenia regularnego.

<form action="" method="post" novalidate>
  <ul class="messages"></ul>
  <div>
    <label>
      Imię
      <input name="firstName" required />
    </label>
  </div>
  <div>
    <label>
      Nazwisko
      <input name="lastName" required />
    </label>
  </div>
  <div>
    <label>
      Kod pocztowy
      <input name="zip" pattern="^[0-9]{2}-[0-9]{3}$" required />
    </label>
  </div>
  <div><button type="submit">Wyślij</button></div>
</form>
// Wyszukujemy formularz
const form = document.querySelector("form");
// Uzyskujemy tablicę z elementami formularza
const fields = Array.from(form.elements);

form.addEventListener("submit", e => {
  e.preventDefault();
// Wyszukujemy element o nazwie "zip"
  const zipField = fields.find(field => field.name === "zip");

// Jeśli pole z kodem pocztowym nie jest zgodne ze wzorem (regexem), to wyświetlamy komunikat o błędzie
  if (!/^[0-9]{2}-[0-9]{3}$/.test(zipField.value)) {
    alert("Nieprawidłowy kod pocztowy")
  }
})

 Metoda reduce()

Metoda reduce() służy do iteracji po elementach tablicy i agregacji ich wartości w celu uzyskania pojedynczego wyniku. Może być używana m.in. do sumowania czy obliczania średniej.

 Jak działa reduce()

Iteracja i akumulacja

Metoda ta przechodzi przez każdy element tablicy i wykonuje na nim określone przez nas w callbacku operacje. Dodatkowo akumuluje przekazane wartości w jedną końcową wartość. O tym, jakim typem danych ma być wartość końcowa (liczbą, obiektem, tablicą itd.), decydujemy sami.

Dwa parametry w callbacku – akumulator i aktualna wartość

Funkcja przekazywana do reduce() przyjmuje dwa argumenty: akumulator i aktualny element tablicy.

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);

W ciele funkcji określamy, jakie operacje należy wykonać na obecnych wartościach, i jak zaktualizować wartość akumulatora.

Drugi parametr metody reduce(), czyli początkowa wartość akumulatora

Jako drugi argument po funkcji redukującej (callbacku) możemy przekazać początkową wartość akumulatora (w przykładzie poniżej to 0). Określa ona, czym powinien być akumulator przed rozpoczęciem iteracji.

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
Uwaga: jeśli nie ustalisz początkowej wartości akumulatora, to zostanie w tym celu użyty pierwszy element tablicy, a iteracja rozpocznie się od drugiego elementu tablicy. Jeżeli jednak tablica okaże się pusta, to otrzymamy błąd (Reduce of empty array with no initial value). Dzięki ustawieniu wartości początkowej nawet w razie pustej tablicy błędu nie będzie – zwrócona zostanie wartość początkowa.

 Przykład użycia reduce()

Tworzysz sklep, w którym produkty jako obiekty trafiają do koszyka. Aby podsumować kwotę do zapłaty, możesz skorzystać właśnie z reduce():

const cartItems = [
  { id: 1, name: 'Product 1', price: 10 },
  { id: 2, name: 'Product 2', price: 20 },
  { id: 3, name: 'Product 3', price: 15 },
];

const totalPrice = cartItems.reduce((sum, item) => sum + item.price, 0);
console.log(totalPrice); // 45
Jeśli korzystasz z deklaracji funkcji (a nie skróconego zapisu funkcji strzałkowej), to pamiętaj o zwróceniu akumulowanej wartości za pomocą return, w przeciwnym razie otrzymasz undefined.

Ale uwaga! Wartością końcową, jak wspomnieliśmy, wcale nie musi być liczba. Może to być obiekt, w którym zgromadzimy pogrupowane dane. Zobacz, jak grupować dane za pomocą metody reduce().

 

Przed rozpoczęciem nauki Reacta (albo Vue, Angulara itp.) warto przypomnieć sobie jeszcze, jak działa destrukturyzacja oraz czym jest rozproszenie i parametr reszty.

Przyda Ci się również przypomnienie działania metody sort(), którą omawiam w osobnym artykule.

 Wyzwanie!

Nie wiesz, czy możesz już zacząć naukę Reacta? 🔥 Podejmij wyzwanie i zdobądź odpowiedź: „Czy jestem gotowy na Reacta?”.

Udostępnij ten artykuł:

Mentoring to efektywna nauka pod okiem doświadczonej osoby, która:

  • przekazuje Ci swoją wiedzę i nadzoruje Twoje postępy w zdobywaniu umiejętności,
  • uczy Cię dobrych praktyk i wyłapuje złe nawyki,
  • wspiera Twój rozwój i zwiększa zaangażowanie w naukę.

Mam coś dla Ciebie!

W każdy piątek rozsyłam motywujący do nauki programowania newsletter!

Dodatkowo od razu otrzymasz ode mnie e-book o wartości 39 zł. To ponad 40 stron konkretów o nauce programowania i pracy w IT.

PS Zazwyczaj wysyłam 1-2 wiadomości na tydzień. Nikomu nie będę udostępniał Twojego adresu e-mail.