Tablica to uporządkowana lista
Tablice w JavaScript przechowują uporządkowaną sekwencję wartości. Wartości mogą być dowolnego typu (liczby, stringi, obiekty, a nawet inne tablice) i nie muszą być tego samego typu. Tablicę tworzysz za pomocą nawiasów kwadratowych:
Tej składni literału użyjesz w 99% przypadków. Istnieje też new Array(...), ale ma pułapkę: new Array(3) tworzy tablicę o długości 3 bez żadnych faktycznych elementów, a nie [3]. Trzymaj się [].
Indeksowanie zaczyna się od zera
Do elementów odwołujesz się po pozycji, licząc od 0:
Zwróć uwagę na dwie rzeczy. Po pierwsze, sięgnięcie poza koniec tablicy nie rzuca błędu, tylko zwraca undefined. To częste źródło błędów w stylu "czemu to jest undefined?". Po drugie, możesz przypisać wartość do dowolnego indeksu, także za końcem tablicy, a JavaScript chętnie ją rozszerzy:
Pozycje 3 i 4 stają się "pustymi miejscami" (dziurami w rzadkiej tablicy). Długość skacze do 6. Rzadko tego chcesz: to efekt uboczny elastyczności tablic, a nie funkcja, na której warto polegać.
length jest aktualizowane na bieżąco
array.length jest zawsze o jeden większe od najwyższego indeksu. Aktualizuje się automatycznie, gdy dodajesz lub usuwasz elementy:
Ostatnią sztuczkę warto zapamiętać: przypisanie do length przycina tablicę. Ustawienie nums.length = 0 to szybki sposób na opróżnienie jej w miejscu.
push, pop, shift, unshift
Cztery metody do dodawania i usuwania elementów na końcach tablicy:
push(x)dodaje na koniec i zwraca nową długość.pop()usuwa z końca i zwraca usunięty element.unshift(x)dodaje na początek.shift()usuwa z początku.
push/pop są szybkie. shift/unshift muszą przenumerować wszystkie pozostałe elementy, więc na dużych tablicach są wolniejsze: przy codziennych rozmiarach nie ma to znaczenia, ale warto o tym wiedzieć, gdy pracujesz z milionami elementów.
slice vs splice
Te dwie metody mają podobne nazwy i zupełnie inne działanie. Jeśli je rozróżnisz, oszczędzisz sobie sporo drapania się po głowie.
slice(start, end) zwraca kopię fragmentu tablicy. Oryginał zostaje nietknięty. end nie wchodzi do wyniku:
splice(start, deleteCount, ...items) modyfikuje tablicę. Może usuwać, wstawiać albo jedno i drugie, a zwraca to, co usunęło:
Zasada praktyczna: slice to jak odkrojenie plasterka z bochenka, czyli kopia. Splice to jak montaż taśmy filmowej (wycinanie i wklejanie), czyli zmiana oryginału.
Wyszukiwanie: indexOf, includes, find
Trzy sposoby na wyszukanie czegoś, do różnych sytuacji:
indexOf(x)zwraca pozycję albo-1, jeśli nic nie znajdzie. Przydaje się, gdy potrzebujesz indeksu.includes(x)zwraca wartość logiczną. Czytelniejsze, gdy chcesz tylko wiedzieć "czy to tu jest?". Poprawnie obsługuje teżNaN, czegoindexOfnie robi.find(predicate)wywołuje funkcję dla każdego elementu i zwraca pierwszy pasujący. To wybór dla tablic obiektów, gdzieindexOfiincludessprawdzają tylko ścisłą równość.
Przechodzenie pętlą po tablicy
Kilka dobrych sposobów, każdy do innej sytuacji:
for...of to domyślny wybór: czytelny, działa z każdym obiektem iterowalnym i daje bezpośrednio wartość. forEach sprawdza się, gdy potrzebujesz też indeksu i nie przerywasz pętli wcześniej (z forEach nie da się wyjść przez break). Klasyczne for z indeksem jest rozwlekłe, ale daje pełną kontrolę: używaj go, gdy musisz pomijać elementy, iterować od końca albo jedno i drugie.
Pętla, której lepiej unikać: for...in. Iteruje po kluczach i uwzględnia odziedziczone właściwości. Służy do obiektów, nie do tablic.
Kopiowanie i łączenie
Tablice są wartościami referencyjnymi. Przypisanie jednej do drugiej nie tworzy kopii, tylko dwie nazwy dla tej samej tablicy:
Żeby naprawdę skopiować tablicę, użyj operatora spread albo slice():
Oba sposoby dają kopię płytką: tablica najwyższego poziomu jest nowa, ale jeśli elementy są obiektami, to te obiekty nadal są współdzielone. Spread to też najczytelniejszy sposób na łączenie tablic:
Tablice obiektów
W prawdziwym kodzie większość tablic przechowuje obiekty. Działają te same metody, ale dopasowywanie robi się ciekawsze:
filter zwraca nową tablicę elementów spełniających predykat. map zwraca nową tablicę, w której każdy element jest przekształcony. Łączenie ich w łańcuch to chleb powszedni pracy z tablicami obiektów, a następna strona dokumentacji omawia tę rodzinę metod dokładniej.
Tablice vs obiekty
Prosty model myślowy: używaj tablicy, gdy liczy się kolejność i pracujesz z listą rzeczy tego samego rodzaju. Używaj obiektu (albo Map), gdy odwołujesz się do rzeczy po nazwie. "Pierwszy, drugi, trzeci" to terytorium tablic. "Znajdź użytkownika o id 42" to terytorium obiektów albo Map.
Możesz je łączyć (tablice obiektów są wszędzie), ale nie używaj tablicy jako słownika z kluczami ani obiektu jako uporządkowanej listy. Każde z nich dobrze robi jedną rzecz.
Dalej: destrukturyzacja
Wyciąganie wartości z tablic po indeksie (i właściwości z obiektów po nazwie) zdarza się na tyle często, że JavaScript ma do tego osobną składnię. To destrukturyzacja i o niej jest następna strona.
Najczęściej zadawane pytania
Jak utworzyć tablicę w JavaScript?
Użyj literału z nawiasami kwadratowymi: const fruits = ['apple', 'banana']. To idiomatyczny sposób. Konstruktor Array (new Array(3)) istnieje, ale rzadko jest tym, czego chcesz: new Array(3) tworzy tablicę o długości 3 bez żadnych faktycznych elementów, co wiele osób zaskakuje.
Jak usunąć element z tablicy w JavaScript?
Z końca użyj pop(). Z początku użyj shift(). Ze środka użyj splice(index, 1), żeby zmienić tablicę w miejscu, albo filter(...), żeby dostać nową tablicę bez tego elementu. splice zmienia oryginał, filter nie.
Czym różni się slice od splice?
slice(start, end) zwraca płytką kopię fragmentu tablicy i zostawia oryginał w spokoju. splice(start, deleteCount, ...items) modyfikuje oryginał: usuwa elementy, opcjonalnie wstawia nowe i zwraca usunięte. Jedna litera różnicy, zupełnie inne działanie.
Jak sprawdzić, czy wartość jest w tablicy JavaScript?
Użyj array.includes(value): zwraca true albo false i poprawnie obsługuje NaN. indexOf(value) zwraca pozycję albo -1, jeśli nic nie znajdzie, co przydaje się, gdy potrzebujesz też indeksu. Przy bardziej złożonym dopasowaniu sięgnij po some(predicate) albo find(predicate).