Poznaliśmy wspólnie już całkiem dużo elementów języka JavaScript. Były zmienne, pętle, funkcje, typy danych i wiele innych. Jest jeszcze jeden, który stanowi FUNDAMENT dla programów mających robić coś naprawdę efektownego 🧩. Tym brakującym ogniwem jest tablica 🔥! Tablica w języku JavaScript wymagała dokładnego wytłumaczenia dużej ilości zagadnień, stąd też artykuł zrobił się przez to dużo większy, więc w razie czego znajdź sobie trochę więcej czasu na przestudiowanie wszystkiego ⏰.
TABLICA W JĘZYKU JAVASCRIPT TAKŻE POSTANAWIA IŚĆ WŁASNYM TOREM
Ten zawodnik też częściowo łamie ogólnie przyjęte normy wynikające z pierwszego języka wysokiego poziomu w historii, C (opinie są różne co do jego "wysokopoziomowości", natomiast dla mnie jest językiem wysokiego poziomu 🙂) ⚠️. Wyjaśnijmy sobie wpierw cechy charakterystyczne.
CZYM JEST TABLICA W JĘZYKU JAVASCRIPT?
Tablica (ang. array) pełni funkcję przechowalni wielu wartości w jednym miejscu tego samego typu, chociaż w języku JavaScript nie jest to do końca prawdą (wrócimy do tego za moment) 🤯. Przypomina taki "słoik", do którego wrzucamy elementy (będące wartościami nazywanymi "argumentami"), a one są odpowiednio ponumerowane 1️⃣2️⃣3️⃣4️⃣.
Najbardziej podstawową funkcją użycia tablicy jest grupowanie danych. Zamiast pisania 1,000 zmiennych nieznacznie różniących się etykietą (nazwą), możemy umieścić je wszystkie do jednej zmiennej tablicowej o wielkości 1,000 elementów i tam niech sobie siedzą ✅. To z kolei umożliwia nam zastosowanie pętli "for" do obsługi tych danych zamieniając pojedyncze instrukcje (jakie to byłoby okropne pisać 1,000 razy to samo 😱!) 🌟.
Gdybyś był(a) zainteresowany(-a) szczegółami tablicy od strony architektury, zobacz sobie artykuł ukazujący tę strukturę danych od strony teoretycznej ℹ️.
JAK UTWORZYĆ TABLICĘ W JĘZYKU JAVASCRIPT?
Tablica w języku JavaScript inicjowana jest za pomocą pary nawiasów kwadratowych ([]). Wewnątrz nich umieszczamy opcjonalnie elementy, które mają się tam znajdować od samego początku. Wtedy każdy z nich oddzielamy przecinkiem.
Przykład 👇:
const arrayA = []; // pusta tablica
const arrayB = [5, 67, 15, 8]; // tablica wypełniona liczbamiPierwsza tablica jest pusta (nie posiada w sobie żadnych elementów). Druga tablica posiada w sobie kilka liczb całkowitych.
A teraz kolejna informacja ℹ️!
JAKIM TYP DANYCH JEST TABLICA W JĘZYKU JAVASCRIPT?
Tablica w języku JavaScript to w rzeczywistości obiektowy typ danych ("object") 😱! Nie wierzysz? Sprawdź sobie tablicę przy użyciu wywołania metody "console.log" i użycia słowa "typeof" 👇:
const array = [];
console.log(typeof array);Co widzisz 😉?
Powtórzę istotną rzecz: tablica jest zdolna do przechowywania wielu argumentów 🧺. Bardzo często występuje potrzeba dostania się do któregokolwiek z nich celem wykonania jakichś operacji (najczęściej w pętli, lecz nie zawsze ℹ️). Jak to się robi?
JAK UZYSKAĆ DOSTĘP DO ELEMENTÓW TABLICY W JĘZYKU JAVASCRIPT?
Celem dostania się do konkretnego argumentu tablicy, korzystamy z liczby naturalnej, która oznacza numer występowania w kolejności 🔢. Co więcej, liczony jest od zera 🔥!!! To znaczy, że pierwszy argument będzie znajdował się pod numerem 0, drugi pod numerem 1 itd. ⚠️.
Oto przykład uzyskiwania dostępu do pierwszej wartości z tablicy 👇:
const array = [5, 6, 9];
console.log("Pierwsza liczba: " + array[0]);W wielu innych źródłach znajdziesz termin "indeks", który jest ładniejszym sformułowaniem tego numeru w kolejności ✨.
Liczenie od zera pochodzi z języka C i odwoływania się do adresu tablicy w systemie szesnastkowym. Tam indeks jest przesunięciem adresu o N bajtów, w zależności od typu danych tablicy ℹ️. Gdy indeks jest zerowy, to adres wskazuje na początek tablicy, który jednocześnie odpowiada za pierwszy argument. Wraz ze zwiększaniem się indeksu, adresu w pamięci "przesuwa się" coraz bardziej, co będzie oznaczać wskazywanie na kolejne argumenty (albo wyjście poza tablicę ⛔!). Tyle w dużym streszczeniu (a dokładniejsze informacje znajdziesz w tym artykule) 😊.
JAK MODYFIKOWAĆ ELEMENTY TABLICY W JĘZYKU JAVASCRIPT?
Gdy zechcesz zmodyfikować dowolny argument w tablicy, korzystasz z tych samych operatorów przypisania, jakie poznałeś(-aś) podczas tłumaczenia tematu zmiennych 👇:
array[0] = 36;Przy czym ponownie uczulam na uważanie, aby nie wyjść poza ramy tablicy 🫵! Przykładowo dla tablicy 3-elementowej, dopuszczalne indeksy to będą: {0, 1, 2}.
Według zasad dobrego kodu, powinno się unikać modyfikowania pojedynczych elementów dowolnych struktur danych przy użyciu "żywcem" wstawionych indeksów ❌. To jest zła praktyka, ponieważ pokazuje, że polegasz na kolejności elementów, która nie zawsze musi być taką, jaką sobie wyobrażasz 💥!
W zależności od struktury i sytuacji, o wiele lepszą praktyką jest pobieranie pierwszego i/lub ostatniego elementu (stos, kolejka) bądź na podstawie referencji odszukanej przy pomocy podanych kryteriów (filtrowanie przez wyrażenia lambda) ✔️.
CZY "CONST" CHRONI PRZED MODYFIKACJĄ WARTOŚCI ELEMENTÓW TABLICY W JĘZYKU JAVASCRIPT?
"const" i w tym przypadku nie stanowi ochrony przed modyfikacją argumentów tablicy - ono jedynie zabroni przypisywania nowej wartości (poprzez znak równości). To samo, co było przy obiekcie.
JAK ITEROWAĆ PO WSZYSTKICH ELEMENTACH TABLICY W JĘZYKU JAVASCRIPT?
Jak zdążyłem napisać, tablica świetnie komponuje się z pętlą "for". Kiedy potrzebujesz zaprogramować obsługę wszystkich elementów w tablicy, bardzo przydatne okaże się użycie właściwości "length", która zwraca aktualną liczbę argumentów w tablicy 👇:
const array = [5, 6, 9];
console.log(array.length); // 3Wtedy możesz bez problemu przedostać się bezpiecznie do każdej wartości, niezależnie od liczby posiadanych przez nią elementów:
for (let i = 0; i < array.length; ++i) {
console.log(array[i]);
}Zaczynając odliczanie od zera, a kończąc na właściwości "length", pętla przechodzi przez każdy pojedynczy element w tablicy, aż do wyczerpania ✅.
Teraz zaprezentuję parę metod należących do tablicy, które oferują wykonywanie podstawowych operacji tzn. dodawanie i usuwanie z niej elementów (argumentów) oraz wykonywanie poszczególnych operacji na każdym z nich. Poznajcie się 🙂!
JAKIE SĄ PRZYKŁADOWE METODY DOTYCZĄCE TABLICY W JĘZYKU JAVASCRIPT?
Oto 3 przykładowe metody jakie warto znać w kontekście obsługi tablic w języku JavaScript 👇:
- push (dodawanie nowego elementu na koniec tablicy),
- pop (usuwanie i zwracanie elementu z końca tablicy),
- forEach (wykonanie określonych instrukcji dla każdego elementu w tablicy).
PUSH
"push" to wprowadzenie dodatkowego elementu do tablicy na jej sam koniec. Stąd też wymaga podania parametru w postaci elementu, jaki ma się tam znaleźć ℹ️. Przydaje się w momencie, gdy element z jakichś powodów, nie może zostać dodany do tablicy w chwili inicjalizacji (a tak często się zdarza).
To jest przykładowe użycie 👇:
const array = [5, 6, 9];
console.log(array);
array.push(38);
console.log(array);Metoda niczego nie zwraca, więc tylko wykonuje polecenie i tyle 😄.
POP
Metoda "pop" zwraca element z końca tablicy (albo "undefined", jeśli nie ma czego zwrócić ⚠️) jednocześnie usuwając go z tablicy ❌. Oto przykład 👇:
const array = [5, 6, 9];
console.log(array);
const lastElement = array.pop();
console.log(array);
console.log(lastElement);Nie podajemy żadnych parametrów.
FOREACH
Kiedy trzeba wykonać jakąś operację na dowolnym zbiorze danych, to pętla "for" jest pierwszą rzeczą, która przychodzi do głowy 🧠. Jest jeszcze jeden zapis, który to umożliwia.
Każda tablica w języku JavaScript posiada metodę "forEach", która także iteruje po każdym z elementów tablicy, natomiast tutaj nie korzysta ze zmiennej "i" 😲. Za parametr przyjmuje - i tu uwaga - serię instrukcji do wykonania, czyli po prostu funkcję 💥! I ta funkcja musi przyjmować jeden parametr typu "aktualnie badany element" 💡.
Aby pomóc Ci zrozumieć potęgę tej metody, rozpatrzmy kilka przykładów ❤️!
JAK KORZYSTAĆ Z METODY "FOREACH" W JĘZYKU JAVASCRIPT?
"forEach" oczekuje funkcji, która przyjmuje od jednego do trzech parametrów 👇:
- pojedynczy element np. liczba,
- indeks (numer porządkowy aktualnego elementu),
- cała struktura danych, od której wywołuje się "forEach".
Pierwszy parametr musi się znaleźć obowiązkowo, a kolejne dwa są opcjonalne. Ich użyteczność zależy od postawionego problemu. Na przykład do wypisania elementów wystarczy nam tylko pierwszy, natomiast indeks może być potrzebny kiedy chcemy wypisać co drugi element (i % 2 == 0) i wpleść taki warunek w środek funkcji ✔️.
Rozpatrzmy kilka przykładów użycia.
"FOREACH" Z FUNKCJĄ Z JEDNYM PARAMETREM OSADZONĄ W MIEJSCE PARAMETRU (WYRAŻENIE LAMBDA)
Na początek postać, z której najczęściej będziesz korzystać. Osadzenie funkcji prosto w miejsce parametru, którego oczekuje metoda "forEach". Trzymając się tego samego przykładu z wypisywaniem każdego elementu w konsoli, wyżej zdefiniowaną pętlę "for" możemy zamienić na to 👇:
array.forEach(function(element) {
console.log(element);
});albo jeszcze prościej:
array.forEach(element => console.log(element));"Wplecenie" funkcji bezpośrednio w miejsce innej funkcji, nazywamy wyrażeniem lambda ℹ️. Korzystaj z tej postaci wtedy, gdy dana funkcja jest potrzebna tylko w tym jednym miejscu na cały kod źródłowy i nie potrzeba użyć jej gdziekolwiek indziej (po więcej informacji, zapraszam do osobnego materiału 👈).
"FOREACH" Z FUNKCJĄ Z JEDNYM PARAMETREM ZDEFINIOWANĄ NA ZEWNĄTRZ
Drugi przykład: funkcja o tej samej postaci z tą samą instrukcją, tylko zdefiniowana na zewnątrz 👇:
function writeElement(element) {
console.log(element);
}
array.forEach(writeElement);I taki zapis będzie miał sens, gdy ta sama funkcja będzie potrzebna jeszcze w paru innych miejscach w kodzie.
Zauważ, że w miejsce parametru metody "forEach" wprowadzona została sama nazwa funkcji bez żadnych nawiasów okrągłych 😮! Podajemy samą nazwę, czyli referencję do funkcji, ponieważ przekazujemy samą informację co ma się wywołać, a wywoływanie odbywa się już w środku (automatycznie) 🔥.
"FOREACH" Z FUNKCJĄ ZE WSZYSTKIMI PARAMETRAMI ZDEFINIOWANYMI NA ZEWNĄTRZ
Ostatni przykład: ta sama funkcja, tylko akceptująca wszystkie 3 parametry, zamiast jednego 👇:
function writeElement(element, index, array) {
console.log("Element: " + element);
console.log("Indeks: " + index);
console.log("Struktura: " + array);
}
array.forEach(writeElement);Gdy to sobie odpalisz, to zobaczysz, że oprócz wypisywania każdego elementu po kolei, pojawią się jeszcze dwie informacje:
- aktualna wartość "wbudowanego" licznika indeksu (przypominam, że zaczyna liczyć od zera),
- aktualny stan tablicy, od której wywołano metodę "forEach".
Nie musisz wszystkich definiować na wyrost. Korzystaj z jednego, z dwóch albo ze wszystkich tylko wtedy, gdy są Ci naprawdę potrzebne 😉! To nie zostanie uznane za błąd składniowy 👍!
Na koniec artykułu, aby było kolorowo, skonfrontujemy sobie tablicę występującą w języku JavaScript z tym, jak wygląda tablica w większości innych równie często wykorzystywanych języków. Głównie będę mieć na myśli takie języki, jak 👇:
CZYM SIĘ RÓŻNI TABLICA W JĘZYKU JAVASCRIPT OD INNYCH (NIEKTÓRYCH) JĘZYKÓW?
Tablica w języku JavaScript różni się dwiema istotnymi kwestiami, które nie są widziane w większości innych języków programowania 👇:
- tablica może zmieniać swój rozmiar dynamicznie (w trakcie działania programu),
- tablica może przyjmować elementy różnych typów danych.
A teraz rozwinę te 2 punkty 🔥!
ROZCIĄGLIWOŚĆ
W języku JavaScript możemy swobodnie dodawać elementy do tablicy i je usuwać. Tyle tylko, że to nie leży w naturze tablicy 😱!
Należy wiedzieć, że formalnie to jest struktura statyczna ℹ️. Oznacza to, że definicja jej wielkości określana jest na poziomie pisania kodu i jest ona niezmienna. W celu późniejszego dostosowania wielkości, trzeba stworzyć całkowicie nową tablicę. Tablica w języku JavaScript to nie jest zwyczajna tablica. To jest w gruncie rzeczy "tablica na sterydach" 😄.
JavaScript lubi mocno odstawać od ogólnie przyjętych norm, co napisałem już dużo wcześniej 😅. Tablica jaka tu występuje jest "rozciągliwa", więc mimo tego, że sama w sobie nie posiada możliwości "ustawiania" długości po inicjalizacji jak się chce, to jest w stanie to robić.
To tak naprawdę złamanie jednej z przyjętych norm jakie panują od czasów języka C, choć JavaScript wcale nie jest osamotniony (język Lua też posiada taką rozciągliwą tablicę, tak jak każdy inny język interpretowany ℹ️). To nie są żadne sztuczki Merlina, tylko charakterystyczna cecha jednej ze struktur danych, jaką jest lista dynamiczna 😱.
Lista dynamiczna przechowuje dane tak samo jak tablica (tylko już bez indeksów), z tym, że jej rozmiar może się dowolnie zmieniać podczas działania programu ℹ️! Nawet możesz nie mieć pojęcia jak bardzo JavaScript wyręcza Cię od brudnej roboty 💦. W warunkach języka C, trzeba umieć operować na wskaźnikach, bo tylko one otwierają drogę do modyfikacji rozmiarów listy w trakcie działania programu. A tu chlast 🔪 - jedna instrukcja i już niczym nie musimy się przejmować 😀.
Wniosek: tablica w języku JavaScript to tak naprawdę lista dynamiczna mogąca elastycznie zmieniać rozmiary w trakcie działania programu (metody "push" i "pop").
WIELE TYPÓW W JEDNYM MIEJSCU
Oto drugie odstępstwo od normy. Przyjęło się w wielu językach o silnej typizacji, że tablica ma prawo przechowywać obiekty tylko JEDNEGO typu i to w dodatku ściśle określonego podczas jej deklaracji. JavaScript nie narzuca takiego obowiązku i umożliwia wstawianie wszystkiego jak leci. Czy to łańcuchy znaków, czy wartości logiczne, wolno Ci umieszczać wszystko bez ograniczeń 🙂.
Natomiast warto sobie zadać pytanie czy aby na pewno to dobrze, że język pozwala na coś takiego. Jak potem zaprogramujesz pętlę mającą obsłużyć każdy bez wyjątku argument? Wykrywanie typu elementu, dobieranie metody, ewentualne jakieś weryfikacje, masakra 😰! Ja bym sobie nie zwalał takich kłopotów na kark i mimo wszystko trzymał się jednego typu danych. Obiekty do obiektów, łańcuchy do łańcuchów i pętla na każdy ze zbiorów z osobna. Tobie radzę robić tak samo 🫵.
Wniosek: tablica w języku JavaScript potrafi przechowywać wiele wartości RÓŻNYCH typów (choć NIE POLECAM stosowania tej praktyki 🚫).
Tablica będąca tak naprawdę listą dynamiczną typu obiektowego, to miejsce do składowania wielu elementów różnych typów.
Tyle informacji wystarczy, aby wiedzieć do czego jest zdolna tablica w języku JavaScript 📖. Sporo tego 😄!