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.
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 funkcjaWszystkie 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.
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);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.
Co wypisze ten kod?
const ceny = [100, 250, 40];
const zRabatem = ceny.map((c) => c * 0.9);
console.log(zRabatem, ceny);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}`));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ę.
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 3find, 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.
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));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?”.
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));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.
Co wypisze ten kod?
const ceny = [20, 30, 50];
const suma = ceny.reduce((acc, c) => acc + c, 0);
console.log(suma);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);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”).
Co wypisze ten kod?
const liczby = [10, 9, 100, 1];
console.log(liczby.sort());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));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.
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);| Zmieniają tablicę (mutują) | Zwracają nową, oryginał nietknięty |
|---|---|
push, pop, shift, unshift | map, filter, slice, concat |
splice, sort, reverse, fill | toSorted, 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.
Co wypisze ten kod?
const wynik = [1, 2, 3, 4]
.map((x) => x * 2)
.filter((x) => x > 2);
console.log(wynik);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);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.
<label>Kategoria:
<select id="kategoria">
<option value="wszystkie">wszystkie</option>
<option value="ekrany">ekrany</option>
<option value="akcesoria">akcesoria</option>
</select>
</label>
<label>Sortuj:
<select id="sortowanie">
<option value="nazwa">po nazwie</option>
<option value="cena">po cenie</option>
</select>
</label>
<ul id="lista"></ul>
<p id="podsumowanie"></p>body { font-family: system-ui, sans-serif; }
li { display: flex; justify-content: space-between; max-width: 300px; padding: 4px 0; border-bottom: 1px solid #ddd; }
.brak { color: #999; text-decoration: line-through; }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();Ściąga
| Metoda | Zwraca | Do czego | Przykład |
|---|---|---|---|
forEach(fn) | undefined | wykonać coś dla każdego | tab.forEach((x) => console.log(x)) |
map(fn) | nowa tablica (ta sama długość) | przepisać każdy element | ceny.map((c) => c * 1.23) |
filter(fn) | nowa tablica (krótsza lub równa) | wybrać pasujące | oceny.filter((o) => o >= 3) |
find(fn) | element lub undefined | pierwszy pasujący | prod.find((p) => p.id === 2) |
findIndex(fn) | indeks lub -1 | gdzie jest pierwszy pasujący | prod.findIndex((p) => p.cena > 100) |
findLast(fn) | element lub undefined | ostatni pasujący (ES2023) | logi.findLast((l) => l.blad) |
some(fn) | true/false | czy choć jeden | pola.some((p) => p === '') |
every(fn) | true/false | czy wszystkie | oceny.every((o) => o >= 2) |
reduce(fn, start) | jedna wartość | zsumować/zliczyć/zbudować | ceny.reduce((s, c) => s + c, 0) |
sort(cmp) | ta sama tablica, zmieniona | posortować w miejscu | tab.sort((a, b) => a - b) |
toSorted(cmp) | nowa tablica | posortowana kopia (ES2023) | tab.toSorted((a, b) => b - a) |
a.localeCompare(b, 'pl') | liczba | komparator napisów po polsku | .sort((a, b) => a.localeCompare(b, 'pl')) |
includes(x) | true/false | czy zawiera wartość | tagi.includes('js') |
at(-1) | element | ostatni element | tab.at(-1) |
flat(), flatMap(fn) | nowa tablica | spłaszczyć zagnieżdżone | [[1], [2, 3]].flat() → [1, 2, 3] |
Object.groupBy(tab, fn) | obiekt grup | pogrupować (ES2024) | Object.groupBy(u, (x) => x.klasa) |
map(fn).join('') | napis | lista → HTML | el.innerHTML = tab.map(naLi).join('') |
Zadania
Oceny z semestru
Dana jest tablica oceny = [3, 5, 2, 4, 5, 1, 4]. Bez ani jednej pętli for policz i wypisz:
- tablicę ocen pozytywnych (≥ 2),
- liczbę piątek,
- średnią wszystkich ocen zaokrągloną do dwóch miejsc,
- czy jest choć jedna jedynka,
- czy wszystkie oceny są ≤ 6.
Pokaż rozwiązanie
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));Koszyk sklepu
Koszyk to tablica obiektów { nazwa, cena, ilosc }. Napisz trzy funkcje, każda w jednej instrukcji return z metodami tablic:
wartoscKoszyka(koszyk)– sumacena * ilosc,najdrozszy(koszyk)– nazwa produktu o najwyższej cenie jednostkowej (użyjtoSortedlubreduce),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); gdynowaIloscto 0, produkt ma zniknąć z koszyka.
Pokaż rozwiązanie
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));Ranking klasy
Masz listę uczniów z ocenami z kilku przedmiotów:
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
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 sredniaStatystyki 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 }(jednymreduce),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:
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
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));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ź.
Co wypisze ten kod?
const w = [1, 2, 3].forEach((x) => x * 2);
console.log(w);Co wypisze ten kod?
const t = [5, 8, 12].map((x) => { x + 1; });
console.log(t);Który zapis sortuje tablicę liczb t rosnąco i NIE zmienia oryginału?
Co zwróci [4, 9, 16].find((x) => x > 5)?
Co wypisze ten kod?
const s = ['a', 'b', 'c'].reduce((acc, x) => acc + x.toUpperCase(), '>');
console.log(s);Co wypisze ten kod?
const pola = ['Jan', '', 'Nowak'];
console.log(pola.some((p) => p === ''), pola.every((p) => p !== ''));Co wypisze ten kod?
const t = [3, 1, 2];
const u = t.sort((a, b) => a - b);
console.log(t, u === t);Co wypisze ten kod?
const r = [10, 20, 30, 40]
.filter((x) => x > 15)
.map((x) => x / 10);
console.log(r);Jaki będzie wynik [].reduce((a, b) => a + b)?
Które wyrażenie zbuduje z tablicy imiona napis HTML z elementami li bez przecinków między nimi?