Typy proste i referencyjne w JavaScripcie

W tym wpisie przedstawie co nieco o typach danych w JSie. Większość osób zaczynających przygodę z JavaScriptem kiedy słyszy o typach danych myśli o typach „number”, „boolean” itp. Mi chodzi o coś zupełnie innego.

Zanim przejdę do szczegółów, spójrzmy na przykład:

Tworzymy nową zmienną, którą nazywamy ‚num’ i przypisujemy jej wartość 1. Następnie tworzymy kolejną zmienną ‚secondNum’, której przypisujemy wartość zmiennej ‚num’. Na koniec wypisujemy obie zmienne w konsoli. Jak pewnie każdy się spodziewał konsola wyrzuca nam dwie jedynki.

Lecimy dalej. W trakcie pracy programu, zmienna ‚secondNum’ otrzymuje nową wartość:

Gdy teraz wypiszemy obie zmienne do konsoli, otrzymamy wyniki 1 i 2.

Wszystko jasne, nic prostszego. W końcu zmienna ‚num’ ma wartość 1, tak jak jej to przypisaliśmy na samym początku, a zmienna ‚secondNum’ ma wartość nową wartość – 2.
Póki co wszystko się zgadza i jest logiczne. Kontynuujmy przykład. Tworzymy nowy program, sytuacja jest podobna, jednak zamiast zwykłych zmiennych potrzebujemy tablic. Jedna do przechowywania danych a druga do manipulowania nimi (wyobraźmy sobie, że z jakiegoś powodu, oryginalna tablica nie może zostać zmieniona)

znowu widzimy wyświetlone w konsoli dwa identyczne zestawy wartości, super, wszystko działa!

Podobnie jak w pierwszym przykładzie, w trakcie pracy programu, tablica do manipulowania danymi zostaje zmieniona

ale kiedy chcemy wypisać stan obu tablic, do konsoli, dzieję się coś dziwnego. Oto co zobaczymy:

Zmieniliśmy tylko tablice ‚psyAux’! Dlaczego tablica ‚psy’ też się zmieniła? Program siada 🙁
Szok i niedowierzanie!

Co ten javascript to ja nawet nie…
Dla niektórych to zachowanie może być oczywiste, ale bardzo wielu nowicjuszy zmaga się bezskutecznie, z próbą zrozumienia tego zjawiska (a prawdziwie schodki zaczynają się, kiedy przekazujemy zmienne jako argumenty funkcji, ale nie wyprzedajmy faktów…)

Odpowiedź jest prosta: Typy proste (primitives) i typy referencyjne (references). Co to oznacza? Typy proste służą do zapisywania, jak nazwa wskazuje, prosty danych, natomiast typy referencyjne do zapisywania złożonych obiektów (a właściwie odnośników do nich). Programiści innych języków, szczególnie C lub C++, na pewno już rozumieją o co chodzi. W tych językach mamy pojęcie stosu i sterty, dwóch rodzajów pamięci (swoją drogą każdemu programiście ta wiedza może się przydać, nie tylko programistom C). Na stosie zapisywane są zmienne typy prostego, a referencje na stercie. Nie będę się tutaj zagłębiał w szczegóły, ale podział ten ma na celu zaoszczędzenie zużycia przez program pamięci (zachęcam do poczytania na ten temat 🙂 ).
W JavaScripcie działa to bardzo podobnie jednak zamiast stosu i sterty mamy obiekt zmiennych. W obiekcie tym klucze to nazwy zmiennych a wartości to … wartości 🙂 W przypadku typów prostych (zajmujących „mało miejsca”) wartością jest faktyczna wartość zmiennej, natomiast jeśli chodzi o typy referencyjne wartością jest adres wskazujący na miejsce, w pamięci, w którym znajdują się dane obiektu (nierzadko zajmujących „dużo miejsca”). Dzięki temu w podręcznej pamięci aplikacji, mamy zajęte „mało miejsca”.

Typy proste

No dobra ale co to wszystko znaczy dla nas? Spójrzmy jeszcze raz na nasz pierwszy przykład. Zmienne ‚num’ i ‚secondNum’ to typy proste (skąd to wiem? trzeba to umieć na pamieć, listę do wkucia podam za chwilę 🙂 ). Oznacza to, że nazwy zmiennych wskazują bezpośrednio na wartości.
Kiedy skopiowaliśmy wartość zmiennej ‚num’ do zmiennej ‚secondNum’ (przy pomocy operatora ‚=’), do nazwy zmiennej ‚secondNum’ została przypisana wartość 1. Stan naszych zmiennych wyglądał tak jak na obrazku, po lewej klucz (nazwa zmiennej), po prawej wartość.
zmienne1
A kiedy nadpisaliśmy zmienną ‚secondNum’ sytuacja wyglądała tak:
zmienne2
Tak właśnie zachowują się typy proste. Można powiedzieć, że każda zmienna zawierająca typ prosty, jest niezależna. Skąd wiadomo czy typ jest prosty czy referencyjny, trzeba wiedzieć i już 🙂

Oto lista typów prostych:

  • string
  • number
  • boolean

dodatkowa są też

  • null
  • undefined

Ale tymi dwoma rzadko operujemy, przynajmniej na początku. Lista nie jest długa, więc myślę, że każdy da rade zapamiętać 🙂

Typy referencyjne

Lista typów referencyjnych jest prostsza do zapamiętania. Typy referencyjne to cała reszta 🙂 czyli obiekty. W naszym wypadku tablica też jest obiektem, specjalnego typu ale jest (temat na inny post).
Kiedy tworzymy zmienną typu referencyjnego, jako wartość zapisywana jest nie „treść” obiektu, lecz adres wskazujący na jego położenie. Dlatego kopiowanie takiej zmiennej do innej zmiennej, nie kopiuje obiektu, lecz adres do niego. W naszym schemacie tablice z psami wyglądają tak:
zmienne3
Obie zmienne wskazują na ten sam obiekt! Dlatego kiedy zmieniamy jedną tablicę, zmienia się również druga. A Tak naprawdę, to tablica zawsze była tylko jedna!

Spotkałem się też z nazywaniem tego zjawiska „płytką kopią” (shallow copy). Jest to jakieś wytłumaczenie, ale uważam, że lepiej jest wiedzieć co tak naprawdę się dzieję 🙂

Mam nadzieję, wyjaśniłem czym są typy proste oraz referencyjne w JavaScripcie i przydadzą się wam te informacje i dzięki temu unikniecie frustracji podczas zabawy z Javascriptem 🙂

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *