W języku JavaScript tablice (ang. arrays) służą do przechowywania uporządkowanych list wartości:
liczb, łańcuchów, obiektów, a nawet innych tablic. Są dynamiczne, mają wbudowane metody i stanowią fundament pracy z danymi.
Tworzenie tablic i podstawy składni
Najczęściej tablice tworzymy za pomocą nawiasów kwadratowych []:
const puste = [];
const liczby = [1, 2, 3];
const miks = [1, 'Ala', { imie: 'Jan' }, [10, 20]];
Dostęp do elementów i długość
Elementy indeksujemy od zera. Właściwość length zwraca aktualną liczbę elementów:
const kolory = ['czerwony', 'zielony', 'niebieski'];
kolory[0]; // 'czerwony'
kolory[kolory.length - 1]; // ostatni element
kolory.length; // 3
Dodawanie i usuwanie elementów
push(...)– dodaje na koniec;pop()– usuwa z końca.unshift(...)– dodaje na początek;shift()– usuwa z początku.splice(index, ile, ...nowe)– wstawia/usuwa w środku (modyfikuje tablicę).slice(start, end)– kopiuje fragment (nie modyfikuje oryginału).
const a = [1,2];
a.push(3); // [1,2,3]
a.unshift(0); // [0,1,2,3]
a.pop(); // [0,1,2]
a.splice(1, 1, 9); // [0,9,2]
const b = a.slice(0, 2); // [0,9]
Iteracja po tablicach
Do przechodzenia po elementach możesz użyć pętli for, for...of lub metod iteracyjnych:
const liczby = [1,2,3];
// klasyczny for for (let i = 0; i < liczby.length; i++) { console.log(liczby[i]);
}
// for...of for (const n of liczby) { console.log(n);
}
// forEach
liczby.forEach((n, i) => console.log(i, n));
Mapowanie, filtrowanie i redukcja
Funkcyjne metody zwracają nowe tablice lub wartość będącą wynikiem agregacji:
const ceny = [10, 20, 30];
const zVat = ceny.map(c => c * 1.23);
// [12.3, 24.6, 36.9]
const drogie = zVat.filter(c => c > 20); // [24.6, 36.9]
const suma = zVat.reduce((acc, c) => acc + c, 0); // 73.8
Wyszukiwanie i sprawdzanie
includes(x)– czy tablica zawiera elementx.indexOf(x)/lastIndexOf(x)– indeks (lub-1, gdy brak).find(fn)– zwraca pierwszy pasujący element.some(fn)/every(fn)– sprawdza warunek dla części/całości.
const users = [
{ id: 1, name: 'Ala' },
{ id: 2, name: 'Ola' }
];
users.find(u => u.id === 2); // {id:2, name:'Ola'}
users.some(u => u.name.startsWith('A')); // true
users.every(u => u.id > 0); // true
Sortowanie i porządkowanie
sort() modyfikuje tablicę w miejscu. Dla liczb i polskich znaków dodaj funkcję porównującą:
const liczby = [10, 2, 33];
liczby.sort((a, b) => a - b); // [2,10,33]
const miasta = ['Żory', 'Warszawa', 'Łódź'];
miasta.sort((a, b) => a.localeCompare(b, 'pl'));
Operator spread, rest i destrukturyzacja
// kopiowanie i łączenie (płytkie)
const a = [1,2];
const b = [...a, 3]; // [1,2,3]
const c = [...a, ...b]; // [1,2,1,2,3]
// rest w parametrach function suma(...nums) { return nums.reduce((acc, n) => acc + n, 0);
}
// destrukturyzacja const [pierwszy, drugi, ...reszta] = c;
Spłaszczanie, tworzenie i tablice “podobne”
flat(n)– spłaszcza zagnieżdżone tablice do poziomun.flatMap(fn)– łączymap()iflat(1).Array.from(iterowalne)– tworzy tablicę z iterowalnych/“array-like”.Array.of(...)– tworzy tablicę z przekazanych wartości.
[1, [2, [3]]].flat(2); // [1,2,3]
Array.from('ABC'); // ['A','B','C']
Array.of(7); // [7]
Tablice wielowymiarowe i przykładowe użycie
const macierz = [
[1, 2, 3],
[4, 5, 6]
];
// suma wszystkich komórek const total = macierz
.flat()
.reduce((acc, n) => acc + n, 0);
Kopiowanie: płytkie vs głębokie
Operacje płytkie (np. [...arr], slice()) kopiują tylko pierwszy poziom – zagnieżdżone obiekty/tabl.
const oryg = [{ x: 1 }];
const kopiaPlytka = [...oryg];
kopiaPlytka[0].x = 99;
oryg[0].x; // 99 - ten sam obiekt w środku
Do głębokiej kopii (proste przypadki) można użyć np. structuredClone(ary) lub JSON.parse(JSON.stringify(ary)) (z ograniczeniami).
Częste pułapki i dobre praktyki
- Nie używaj
delete arr[i]– tworzy “dziurę” i nie przesuwa indeksów. Zamiast tego użyjsplice(). - Pamiętaj, że
sort()i wiele metod modyfikuje tablicę. Jeśli potrzebujesz niezmienności – pracuj na kopii ([...arr]). lengthmożna przyciąć:arr.length = 0opróżni tablicę; ale rób to świadomie.- Równość tablic porównuje referencje:
[1,2] === [1,2]tofalse. Porównuj elementy, nie referencje. for...innie jest do tablic (iteruje po kluczach/łańcuchach prototypu). Używajfor,for...of,forEach.- Pracując z “array-like” (np.
NodeList), użyjArray.from()do konwersji na prawdziwą tablicę. - Dla dużych kolekcji rozważ metody nie-alokujące niepotrzebnych kopii i unikaj zagnieżdżonych pętli O(n²) gdy to możliwe.
Przykład: pipeline na danych
// Zadanie: z listy produktów wybierz aktywne, posortuj po cenie rosnąco
const produkty = [
{ id: 1, nazwa: 'Kompresor', cena: 399, aktywny: true },
{ id: 2, nazwa: 'Membrana', cena: 59, aktywny: false },
{ id: 3, nazwa: 'Zestaw pneumatyczny', cena: 249, aktywny: true }
];
const wynik = produkty
.filter(p => p.aktywny)
.slice() // kopia, by nie modyfikować oryginału przy sortowaniu
.sort((a, b) => a.cena - b.cena)
.map(p => `${p.nazwa} – ${p.cena} zł`);
console.log(wynik); // ["Zestaw pneumatyczny – 249 zł", "Kompresor – 399 zł"]
Tablice vs. obiekty – kiedy co wybrać?
- Użyj tablicy, gdy liczy się kolejność, indeksy liczbowe i operacje na listach.
- Użyj obiektu, gdy potrzebujesz par klucz–wartość z kluczami jako nazwami (np. słowniki).
- Rozważ
Map/Set, gdy ważna jest wydajność operacji wyszukiwania/unikalności.
Nowości i warte uwagi metody
at(index)– czytelny dostęp, wspiera indeksy ujemne:arr.at(-1).toSorted(),toReversed(),toSpliced()– zwracają kopie bez modyfikacji oryginału.with(index, value)– kopia z podmienioną pozycją (bez mutowania oryginału).findLast(),findLastIndex()– wyszukiwanie od końca.
const arr = [1,3,2];
arr.toSorted((a,b) => a-b); // [1,2,3] – oryginał zostaje [1,3,2]
arr.with(1, 99); // [1,99,2]
arr.at(-1); // 2
Podsumowanie
Tablice to elastyczna i potężna struktura danych w JavaScript. Pozwalają wydajnie przechowywać i przetwarzać listy, a bogaty zestaw metod – od prostych (push, slice) po funkcyjne (map, filter, reduce) i niemutujące (toSorted, with) – ułatwia pisanie czytelnego, bezpiecznego i wydajnego kodu. Pamiętaj o pułapkach (mutacje, delete, płytkie kopie) i świadomie wybieraj narzędzia – dzięki temu praca z danymi będzie przyjemna i przewidywalna.
