Przejdź do treści

Temat 22 · 2 × 45 min

Metody tablic wyższego rzędu

W lekcji o tablicach każde zadanie rozwiązywałeś pętlą for: suma, filtrowanie, szukanie, przepisywanie elementów. To działa, ale za każdym razem piszesz od zera to samo rusztowanie: licznik, warunek, pustą tablicę wynikową, push. Metody wyższego rzędu (higher-order methods) to gotowe pętle wbudowane w tablicę: ty podajesz tylko co zrobić z jednym elementem, a metoda zajmuje się iteracją. Kod staje się krótszy, czytelniejszy i trudniej w nim o błąd off-by-one. Tak wygląda praktycznie cały współczesny kod frontendowy – dane z API to tablica obiektów, którą filtrujesz, sortujesz i zamieniasz na HTML.

Funkcja jako wartość

W JavaScripcie funkcja to zwykła wartość – jak liczba czy napis. Można ją przypisać do zmiennej, włożyć do tablicy, a przede wszystkim przekazać innej funkcji jako argument. Funkcja przekazana w ten sposób nazywa się callback (funkcja zwrotna); funkcja, która ją przyjmuje, to funkcja wyższego rzędu. Znasz to już z addEventListener('click', obsluzKlik) – przekazujesz funkcję, a przeglądarka wywołuje ją później.

funkcja-jako-wartosc.js
const podwoj = (x) => x * 2;
const dodajTrzy = (x) => x + 3;

// funkcja w zmiennej, w tablicy, jako argument
const operacje = [podwoj, dodajTrzy, Math.sqrt];
console.log(typeof podwoj, operacje.length);

// własna funkcja wyższego rzędu: wywołuje callback dla każdego elementu
function dlaKazdego(tablica, callback) {
  for (let i = 0; i < tablica.length; i++) {
    callback(tablica[i], i);
  }
}

dlaKazdego([10, 20, 30], (wartosc, indeks) => {
  console.log(`[${indeks}] = ${wartosc}`);
});

// przekazujemy funkcję, NIE jej wynik
dlaKazdego([16, 81], Math.sqrt);   // dobrze: Math.sqrt to funkcja
// dlaKazdego([16, 81], Math.sqrt()) // źle: Math.sqrt() to NaN, nie funkcja
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

Wszystkie metody z tej lekcji działają na tej zasadzie: dostają callback i wywołują go dla kolejnych elementów, przekazując (element, indeks, calaTablica). Zwykle używasz tylko pierwszego parametru.

forEach – zrób coś z każdym elementem

forEach to zastępstwo zwykłej pętli, gdy chcesz wykonać efekt uboczny: wypisać, dodać do DOM, zapisać. Nie zwraca nic (undefined) – nie da się jej wyniku przypisać ani nic nią policzyć. Nie da się też przerwać break; jeśli tego potrzebujesz, użyj for…of.

foreach.js
const koszyk = [
  { nazwa: 'Klawiatura', cena: 199 },
  { nazwa: 'Mysz', cena: 89 },
  { nazwa: 'Podkładka', cena: 25 },
];

koszyk.forEach((produkt, i) => {
  console.log(`${i + 1}. ${produkt.nazwa} – ${produkt.cena} zł`);
});

// forEach nic nie zwraca – to częste zaskoczenie
const wynik = koszyk.forEach((p) => p.cena);
console.log(wynik);
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

map – przepisz każdy element na nowy

map tworzy nową tablicę tej samej długości, w której każdy element to wynik callbacku dla elementu oryginału. Oryginał zostaje bez zmian. To najważniejsza metoda w tej lekcji: liczby → liczby po przeliczeniu, obiekty → napisy HTML, dane z API → dane dla widoku.

Sprawdź się

Co wypisze ten kod?

const ceny = [100, 250, 40];
const zRabatem = ceny.map((c) => c * 0.9);
console.log(zRabatem, ceny);
map.js
const ceny = [100, 250, 40];

const brutto = ceny.map((c) => c * 1.23);
console.log(brutto);

const sformatowane = ceny.map((c) => `${c.toFixed(2)} zł`);
console.log(sformatowane);

// obiekty → inne obiekty (bez zmiany oryginałów – spread kopiuje)
const produkty = [
  { nazwa: 'Klawiatura', cena: 199 },
  { nazwa: 'Mysz', cena: 89 },
];
const przecenione = produkty.map((p) => ({ ...p, cena: p.cena - 20 }));
console.log(przecenione[0].cena, produkty[0].cena);

// obiekty → tylko jedna właściwość
const nazwy = produkty.map((p) => p.nazwa);
console.log(nazwy);

// map z indeksem
console.log(['a', 'b', 'c'].map((litera, i) => `${i}:${litera}`));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

filter – wybierz elementy spełniające warunek

filter zwraca nową tablicę z tymi elementami, dla których callback zwrócił wartość prawdziwą. Wynik może być krótszy od oryginału, nawet pusty – ale zawsze jest tablicą, więc bezpiecznie można na nim wywołać kolejną metodę.

filter.js
const oceny = [5, 2, 4, 1, 3, 6];
console.log(oceny.filter((o) => o >= 3));           // [5, 4, 3, 6]
console.log(oceny.filter((o) => o > 10));           // [] – nic nie pasuje, ale to tablica

const uczniowie = [
  { imie: 'Ala', klasa: '3TP', srednia: 4.8 },
  { imie: 'Bartek', klasa: '3TI', srednia: 3.1 },
  { imie: 'Celina', klasa: '3TP', srednia: 3.9 },
];
const zTP = uczniowie.filter((u) => u.klasa === '3TP');
console.log(zTP.map((u) => u.imie));

// usuwanie elementu „bez usuwania”: zostaw wszystkie poza jednym
const bezBartka = uczniowie.filter((u) => u.imie !== 'Bartek');
console.log(bezBartka.length, uczniowie.length); // oryginał dalej ma 3
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

find, findIndex, findLast – znajdź jeden element

find zwraca pierwszy element spełniający warunek (sam element, nie tablicę) albo undefined, gdy nic nie pasuje. findIndex zwraca jego indeks albo -1. findLast i findLastIndex (ES2023) szukają od końca. Dla prostego „czy jest w tablicy” wystarczy includes, a dla prymitywów indexOf – find jest dla obiektów i warunków.

find.js
const produkty = [
  { id: 1, nazwa: 'Klawiatura', cena: 199 },
  { id: 2, nazwa: 'Mysz', cena: 89 },
  { id: 3, nazwa: 'Monitor', cena: 899 },
];

const mysz = produkty.find((p) => p.id === 2);
console.log(mysz.nazwa);

const brak = produkty.find((p) => p.id === 99);
console.log(brak);                    // undefined – uwaga przy brak.nazwa!
console.log(brak?.nazwa ?? 'nie znaleziono');

console.log(produkty.findIndex((p) => p.cena > 100));     // 0 – klawiatura
console.log(produkty.findLast((p) => p.cena > 100).nazwa); // Monitor – od końca

// includes dla prymitywów, at(-1) dla ostatniego elementu
const tagi = ['js', 'html', 'css'];
console.log(tagi.includes('css'), tagi.at(-1));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

some i every – sprawdź warunek dla całości

Obie zwracają true/false. some – czy choć jeden element spełnia warunek; every – czy wszystkie. Przerywają sprawdzanie, gdy znają odpowiedź. Idealne do walidacji: „czy jakieś pole jest puste?”, „czy wszystkie checkboxy zaznaczone?”.

some-every.js
const pola = ['Jan', 'Kowalski', '', 'jan@example.com'];
console.log(pola.some((p) => p.trim() === ''));   // true – jest puste pole
console.log(pola.every((p) => p.trim() !== ''));  // false

const oceny = [4, 5, 3, 5];
console.log(oceny.every((o) => o >= 3));  // true – zdał wszystko
console.log(oceny.some((o) => o === 6));  // false – ani jednej szóstki

// pusta tablica: every → true, some → false (nic nie zaprzecza / nic nie potwierdza)
console.log([].every((x) => x > 100), [].some((x) => x > 100));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

reduce – sprowadź tablicę do jednej wartości

reduce to najbardziej ogólna metoda: przechodzi po tablicy i „zbiera” wynik w akumulatorze. Callback dostaje (akumulator, element) i zwraca nowy akumulator. Drugi argument reduce to wartość początkowa akumulatora – praktycznie zawsze ją podawaj.

Sprawdź się

Co wypisze ten kod?

const ceny = [20, 30, 50];
const suma = ceny.reduce((acc, c) => acc + c, 0);
console.log(suma);
reduce.js
const koszyk = [
  { nazwa: 'Klawiatura', cena: 199, ilosc: 1 },
  { nazwa: 'Mysz', cena: 89, ilosc: 2 },
  { nazwa: 'Podkładka', cena: 25, ilosc: 3 },
];

// suma wartości koszyka
const razem = koszyk.reduce((suma, p) => suma + p.cena * p.ilosc, 0);
console.log(razem);

// największa cena (akumulator = dotychczasowe maksimum)
const maks = koszyk.reduce((m, p) => (p.cena > m ? p.cena : m), 0);
console.log(maks);

// zliczanie: akumulator jest obiektem
const glosy = ['tak', 'nie', 'tak', 'tak', 'nie'];
const zliczone = glosy.reduce((acc, g) => {
  acc[g] = (acc[g] ?? 0) + 1;
  return acc; // z klamrami trzeba zwrócić akumulator!
}, {});
console.log(zliczone);

// krok po kroku – zobacz, jak zmienia się akumulator
[1, 2, 3].reduce((acc, x) => {
  console.log(`acc=${acc}, x=${x} → ${acc + x}`);
  return acc + x;
}, 0);
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

sort – sortowanie z komparatorem

sort() bez argumentu zamienia elementy na napisy i porównuje je znak po znaku – dlatego [10, 9, 1].sort() daje [1, 10, 9]. Do liczb zawsze podawaj komparator: funkcję (a, b), która zwraca liczbę ujemną, gdy a ma być przed b, dodatnią, gdy po, i 0, gdy są równe. Dla liczb to po prostu a - b (rosnąco) lub b - a (malejąco). Dla napisów z polskimi znakami używaj a.localeCompare(b, 'pl') – zwykłe < porównuje kody znaków, więc ustawi „ą” i „Ł” za „z”, a wielkie litery przed małymi („Z” przed „a”).

Sprawdź się

Co wypisze ten kod?

const liczby = [10, 9, 100, 1];
console.log(liczby.sort());
sort.js
const liczby = [10, 9, 100, 1];
console.log([...liczby].sort());              // leksykograficznie – źle dla liczb
console.log([...liczby].sort((a, b) => a - b)); // rosnąco
console.log([...liczby].sort((a, b) => b - a)); // malejąco

// napisy po polsku
const imiona = ['Żaneta', 'adam', 'Łukasz', 'Celina'];
console.log([...imiona].sort());                                 // kody znaków: wielkie przed małymi, Ł i Ż na końcu
console.log([...imiona].sort((a, b) => a.localeCompare(b, 'pl'))); // alfabetycznie po polsku

// obiekty po właściwości
const produkty = [
  { nazwa: 'Monitor', cena: 899 },
  { nazwa: 'Mysz', cena: 89 },
  { nazwa: 'Klawiatura', cena: 199 },
];
const wgCeny = [...produkty].sort((a, b) => a.cena - b.cena);
console.log(wgCeny.map((p) => p.nazwa));

const wgNazwy = [...produkty].sort((a, b) => a.nazwa.localeCompare(b.nazwa, 'pl'));
console.log(wgNazwy.map((p) => p.nazwa));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

sort zmienia tablicę – toSorted nie

W przykładzie wyżej wszędzie jest [...liczby].sort(…). To nie przypadek: sort (podobnie jak reverse, splice, push) modyfikuje tablicę, na której go wywołujesz, i dodatkowo ją zwraca. Jeśli posortujesz produkty bezpośrednio, stracisz pierwotną kolejność – np. „kolejność dodania” w koszyku. Od ES2023 masz wersje niemutujące: toSorted(), toReversed(), toSpliced() i with(indeks, wartosc). Działają we wszystkich przeglądarkach od połowy 2023 r.

tosorted.js
const oryginal = [3, 1, 2];

const posortowane = oryginal.toSorted((a, b) => a - b);
console.log(oryginal, posortowane);   // oryginał bez zmian

const odwrocone = oryginal.toReversed();
console.log(oryginal, odwrocone);

const zmieniony = oryginal.with(0, 99); // kopia z podmienionym elementem
console.log(oryginal, zmieniony);

// kontrast: sort mutuje
const kopia = [...oryginal];
kopia.sort((a, b) => a - b);
console.log(kopia);
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik
Zmieniają tablicę (mutują)Zwracają nową, oryginał nietknięty
push, pop, shift, unshiftmap, filter, slice, concat
splice, sort, reverse, filltoSorted, toReversed, toSpliced, with
flat, flatMap, [...tab]

Dlaczego to ważne, zobaczysz w lekcji o referencjach i później w React, gdzie zmutowanie stanu „po cichu” to klasyczny błąd.

Łańcuchowanie metod

Skoro filter, map, toSorted zwracają tablice, możesz wywoływać je jedna po drugiej. Czytaj łańcuch z góry na dół jak przepis: wybierz → posortuj → przepisz → połącz. Każdą linię zaczynaj od kropki – tak formatuje to Prettier i tak czyta się w dokumentacjach.

Sprawdź się

Co wypisze ten kod?

const wynik = [1, 2, 3, 4]
.map((x) => x * 2)
.filter((x) => x > 2);
console.log(wynik);
lancuch.js
const produkty = [
  { nazwa: 'Monitor', cena: 899, kategoria: 'ekrany', dostepny: true },
  { nazwa: 'Mysz', cena: 89, kategoria: 'akcesoria', dostepny: true },
  { nazwa: 'Klawiatura', cena: 199, kategoria: 'akcesoria', dostepny: false },
  { nazwa: 'Podkładka', cena: 25, kategoria: 'akcesoria', dostepny: true },
];

// dostępne akcesoria, od najtańszego, jako napisy
const lista = produkty
  .filter((p) => p.dostepny && p.kategoria === 'akcesoria')
  .toSorted((a, b) => a.cena - b.cena)
  .map((p) => `${p.nazwa} (${p.cena} zł)`);
console.log(lista);

// łączna wartość dostępnych produktów
const wartosc = produkty
  .filter((p) => p.dostepny)
  .reduce((suma, p) => suma + p.cena, 0);
console.log(wartosc);

// kolejność ma znaczenie dla wydajności: najpierw filter (mniej elementów), potem map
const drogie = produkty.filter((p) => p.cena > 100).map((p) => p.nazwa);
console.log(drogie);
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

Render listy: map().join(”)

Najczęstszy wzorzec DOM w nowoczesnym kodzie: zamień tablicę danych na tablicę fragmentów HTML (map), sklej w jeden napis (join('')) i wstaw przez innerHTML. Jedna instrukcja zamiast pętli z createElement – wygodne dla list, które generujesz od zera przy każdej zmianie danych. Pamiętaj o join('') – bez argumentu join wstawia między elementy przecinki, które pojawią się na stronie.

Katalog z filtrem i sortowaniem
const produkty = [
  { nazwa: 'Monitor', cena: 899, kategoria: 'ekrany', dostepny: true },
  { nazwa: 'Mysz', cena: 89, kategoria: 'akcesoria', dostepny: true },
  { nazwa: 'Klawiatura', cena: 199, kategoria: 'akcesoria', dostepny: false },
  { nazwa: 'Podkładka', cena: 25, kategoria: 'akcesoria', dostepny: true },
  { nazwa: 'Projektor', cena: 1499, kategoria: 'ekrany', dostepny: false },
];

const selectKategoria = document.getElementById('kategoria');
const selectSortowanie = document.getElementById('sortowanie');
const lista = document.getElementById('lista');
const podsumowanie = document.getElementById('podsumowanie');

function renderuj() {
  const kategoria = selectKategoria.value;
  const sortowanie = selectSortowanie.value;

  const widoczne = produkty
    .filter((p) => kategoria === 'wszystkie' || p.kategoria === kategoria)
    .toSorted((a, b) =>
      sortowanie === 'cena' ? a.cena - b.cena : a.nazwa.localeCompare(b.nazwa, 'pl')
    );

  // tablica obiektów → tablica napisów HTML → jeden napis
  lista.innerHTML = widoczne
    .map((p) => `<li class="${p.dostepny ? '' : 'brak'}"><span>${p.nazwa}</span><span>${p.cena} zł</span></li>`)
    .join('');

  const suma = widoczne.filter((p) => p.dostepny).reduce((s, p) => s + p.cena, 0);
  podsumowanie.textContent = `Pozycji: ${widoczne.length}, wartość dostępnych: ${suma} zł`;
}

selectKategoria.addEventListener('change', renderuj);
selectSortowanie.addEventListener('change', renderuj);
renderuj();
Podgląd

Ściąga

MetodaZwracaDo czegoPrzykład
forEach(fn)undefinedwykonać coś dla każdegotab.forEach((x) => console.log(x))
map(fn)nowa tablica (ta sama długość)przepisać każdy elementceny.map((c) => c * 1.23)
filter(fn)nowa tablica (krótsza lub równa)wybrać pasująceoceny.filter((o) => o >= 3)
find(fn)element lub undefinedpierwszy pasującyprod.find((p) => p.id === 2)
findIndex(fn)indeks lub -1gdzie jest pierwszy pasującyprod.findIndex((p) => p.cena > 100)
findLast(fn)element lub undefinedostatni pasujący (ES2023)logi.findLast((l) => l.blad)
some(fn)true/falseczy choć jedenpola.some((p) => p === '')
every(fn)true/falseczy wszystkieoceny.every((o) => o >= 2)
reduce(fn, start)jedna wartośćzsumować/zliczyć/zbudowaćceny.reduce((s, c) => s + c, 0)
sort(cmp)ta sama tablica, zmienionaposortować w miejscutab.sort((a, b) => a - b)
toSorted(cmp)nowa tablicaposortowana kopia (ES2023)tab.toSorted((a, b) => b - a)
a.localeCompare(b, 'pl')liczbakomparator napisów po polsku.sort((a, b) => a.localeCompare(b, 'pl'))
includes(x)true/falseczy zawiera wartośćtagi.includes('js')
at(-1)elementostatni elementtab.at(-1)
flat(), flatMap(fn)nowa tablicaspłaszczyć zagnieżdżone[[1], [2, 3]].flat() → [1, 2, 3]
Object.groupBy(tab, fn)obiekt gruppogrupować (ES2024)Object.groupBy(u, (x) => x.klasa)
map(fn).join('')napislista → HTMLel.innerHTML = tab.map(naLi).join('')

Zadania

Zadanie 1
łatwe

Oceny z semestru

Dana jest tablica oceny = [3, 5, 2, 4, 5, 1, 4]. Bez ani jednej pętli for policz i wypisz:

  1. tablicę ocen pozytywnych (≥ 2),
  2. liczbę piątek,
  3. średnią wszystkich ocen zaokrągloną do dwóch miejsc,
  4. czy jest choć jedna jedynka,
  5. czy wszystkie oceny są ≤ 6.
Pokaż rozwiązanie
oceny.js
const oceny = [3, 5, 2, 4, 5, 1, 4];

const pozytywne = oceny.filter((o) => o >= 2);
console.log('Pozytywne:', pozytywne);

// filter + length – „ile elementów spełnia warunek”
const piatki = oceny.filter((o) => o === 5).length;
console.log('Piątek:', piatki);

const suma = oceny.reduce((s, o) => s + o, 0);
console.log('Średnia:', (suma / oceny.length).toFixed(2));

console.log('Jest jedynka:', oceny.some((o) => o === 1));
console.log('Wszystkie ≤ 6:', oceny.every((o) => o <= 6));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik
Zadanie 2
średnie

Koszyk sklepu

Koszyk to tablica obiektów { nazwa, cena, ilosc }. Napisz trzy funkcje, każda w jednej instrukcji return z metodami tablic:

  • wartoscKoszyka(koszyk) – suma cena * ilosc,
  • najdrozszy(koszyk) – nazwa produktu o najwyższej cenie jednostkowej (użyj toSorted lub reduce),
  • zmienIlosc(koszyk, nazwa, nowaIlosc) – zwraca nowy koszyk, w którym produkt o podanej nazwie ma nową ilość, a reszta jest bez zmian (oryginał nietknięty); gdy nowaIlosc to 0, produkt ma zniknąć z koszyka.
Pokaż rozwiązanie
koszyk.js
const koszyk = [
  { nazwa: 'Klawiatura', cena: 199, ilosc: 1 },
  { nazwa: 'Mysz', cena: 89, ilosc: 2 },
  { nazwa: 'Podkładka', cena: 25, ilosc: 3 },
];

const wartoscKoszyka = (koszyk) => koszyk.reduce((suma, p) => suma + p.cena * p.ilosc, 0);

// toSorted nie zmienia koszyka; [0] to najdroższy po sortowaniu malejąco
const najdrozszy = (koszyk) => koszyk.toSorted((a, b) => b.cena - a.cena)[0]?.nazwa;

// map tworzy nowe obiekty tylko dla zmienionego produktu, filter usuwa zerowe ilości
const zmienIlosc = (koszyk, nazwa, nowaIlosc) =>
  koszyk
    .map((p) => (p.nazwa === nazwa ? { ...p, ilosc: nowaIlosc } : p))
    .filter((p) => p.ilosc > 0);

console.log(wartoscKoszyka(koszyk));    // 199 + 178 + 75 = 452
console.log(najdrozszy(koszyk));        // Klawiatura

const nowy = zmienIlosc(koszyk, 'Mysz', 5);
console.log(nowy[1].ilosc, koszyk[1].ilosc); // 5 2 – oryginał bez zmian

const bezPodkladki = zmienIlosc(koszyk, 'Podkładka', 0);
console.log(bezPodkladki.map((p) => p.nazwa));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik
Zadanie 3
średnie

Ranking klasy

Masz listę uczniów z ocenami z kilku przedmiotów:

JavaScript
const uczniowie = [
  { imie: 'Ala', oceny: [5, 4, 5] },
  { imie: 'Bartek', oceny: [3, 2, 4] },
  { imie: 'Celina', oceny: [4, 4, 4] },
  { imie: 'Darek', oceny: [5, 5, 6] },
];

Zbuduj jeden łańcuch metod, który: dla każdego ucznia policzy średnią (nowy obiekt { imie, srednia } – oryginału nie zmieniaj), odrzuci uczniów ze średnią poniżej 3.5, posortuje malejąco po średniej i zwróci tablicę napisów w formacie 1. Darek – 5.33. Wypisz wynik po jednym w linii.

Pokaż rozwiązanie
ranking.js
const uczniowie = [
  { imie: 'Ala', oceny: [5, 4, 5] },
  { imie: 'Bartek', oceny: [3, 2, 4] },
  { imie: 'Celina', oceny: [4, 4, 4] },
  { imie: 'Darek', oceny: [5, 5, 6] },
];

const srednia = (oceny) => oceny.reduce((s, o) => s + o, 0) / oceny.length;

const ranking = uczniowie
  .map((u) => ({ imie: u.imie, srednia: srednia(u.oceny) })) // nowy obiekt, bez tablicy ocen
  .filter((u) => u.srednia >= 3.5)
  .toSorted((a, b) => b.srednia - a.srednia)                 // malejąco
  .map((u, i) => `${i + 1}. ${u.imie} – ${u.srednia.toFixed(2)}`); // indeks dostępny w map

ranking.forEach((linia) => console.log(linia));
console.log(uczniowie[0]); // oryginał bez pola srednia
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik
Zadanie 4
trudne

Statystyki sprzedaży

Sprzedaż sklepu to tablica transakcji { produkt, kategoria, kwota, miesiac }. Napisz funkcję raport(sprzedaz), która zwraca obiekt:

  • razem – suma wszystkich kwot,
  • wgKategorii – obiekt { kategoria: suma } (jednym reduce),
  • najlepszyMiesiac – nazwa miesiąca o największej sumie sprzedaży,
  • produkty – posortowana alfabetycznie (po polsku) tablica unikalnych nazw produktów (podpowiedź: new Set(tablica) usuwa duplikaty, a [...set] zamienia z powrotem na tablicę).

Dane testowe:

JavaScript
const sprzedaz = [
  { produkt: 'Żarówka', kategoria: 'dom', kwota: 20, miesiac: 'styczeń' },
  { produkt: 'Lampa', kategoria: 'dom', kwota: 150, miesiac: 'luty' },
  { produkt: 'Kabel', kategoria: 'elektronika', kwota: 35, miesiac: 'styczeń' },
  { produkt: 'Żarówka', kategoria: 'dom', kwota: 20, miesiac: 'luty' },
  { produkt: 'Ładowarka', kategoria: 'elektronika', kwota: 80, miesiac: 'marzec' },
];
Pokaż rozwiązanie
raport.js
const sprzedaz = [
  { produkt: 'Żarówka', kategoria: 'dom', kwota: 20, miesiac: 'styczeń' },
  { produkt: 'Lampa', kategoria: 'dom', kwota: 150, miesiac: 'luty' },
  { produkt: 'Kabel', kategoria: 'elektronika', kwota: 35, miesiac: 'styczeń' },
  { produkt: 'Żarówka', kategoria: 'dom', kwota: 20, miesiac: 'luty' },
  { produkt: 'Ładowarka', kategoria: 'elektronika', kwota: 80, miesiac: 'marzec' },
];

// pomocnik: sumuje kwoty według dowolnego klucza → { klucz: suma }
const sumujWg = (tab, klucz) =>
  tab.reduce((acc, t) => {
    acc[t[klucz]] = (acc[t[klucz]] ?? 0) + t.kwota;
    return acc;
  }, {});

function raport(sprzedaz) {
  const razem = sprzedaz.reduce((s, t) => s + t.kwota, 0);
  const wgKategorii = sumujWg(sprzedaz, 'kategoria');

  // obiekt { miesiac: suma } → pary [miesiac, suma] → sortuj malejąco → pierwsza para → nazwa
  const wgMiesiaca = sumujWg(sprzedaz, 'miesiac');
  const najlepszyMiesiac = Object.entries(wgMiesiaca)
    .toSorted(([, a], [, b]) => b - a)[0][0];

  // Set usuwa duplikaty, spread wraca do tablicy, localeCompare sortuje po polsku
  const produkty = [...new Set(sprzedaz.map((t) => t.produkt))]
    .toSorted((a, b) => a.localeCompare(b, 'pl'));

  return { razem, wgKategorii, najlepszyMiesiac, produkty };
}

console.log(raport(sprzedaz));
Konsola
Kliknij „Uruchom”, aby zobaczyć wynik

Zwróć uwagę na destrukturyzację w komparatorze: ([, a], [, b]) => b - a – każdy element to para [miesiac, suma], a my porównujemy tylko sumy.

Test powtórkowy

Test powtórkowy

Metody tablic: 10 pytań, jedna poprawna odpowiedź.

0/0poprawnych
Sprawdź się

Co wypisze ten kod?

const w = [1, 2, 3].forEach((x) => x * 2);
console.log(w);
Sprawdź się

Co wypisze ten kod?

const t = [5, 8, 12].map((x) => { x + 1; });
console.log(t);
Sprawdź się

Który zapis sortuje tablicę liczb t rosnąco i NIE zmienia oryginału?

Sprawdź się

Co zwróci [4, 9, 16].find((x) => x > 5)?

Sprawdź się

Co wypisze ten kod?

const s = ['a', 'b', 'c'].reduce((acc, x) => acc + x.toUpperCase(), '>');
console.log(s);
Sprawdź się

Co wypisze ten kod?

const pola = ['Jan', '', 'Nowak'];
console.log(pola.some((p) => p === ''), pola.every((p) => p !== ''));
Sprawdź się

Co wypisze ten kod?

const t = [3, 1, 2];
const u = t.sort((a, b) => a - b);
console.log(t, u === t);
Sprawdź się

Co wypisze ten kod?

const r = [10, 20, 30, 40]
.filter((x) => x > 15)
.map((x) => x / 10);
console.log(r);
Sprawdź się

Jaki będzie wynik [].reduce((a, b) => a + b)?

Sprawdź się

Które wyrażenie zbuduje z tablicy imiona napis HTML z elementami li bez przecinków między nimi?