Typy danych

Powyżej opisane zostały działania na wartościach liczbowych, znakowych i logicznych. Są to różne typy danych. Typ wartości jaką wstawimy do zmiennej decyduje o tym, jakiego typu jest to zmienna. Możemy to sprawdzić funkcją typeof().

Przykład:

> var zmienna=1;
> typeof(zmienna);
'number'
> var zmienna='abc';
> typeof(zmienna);
'string'
> var zmienna=true;
> typeof(zmienna);
'boolean'
> var zmienna=undefined;
> typeof(zmienna);
'undefined'
> var zmienna=null;
> typeof(zmienna);
'object'
> var zmienna={};
> typeof(zmienna);
'object'

W przykładzie tym pokazano typy danych stosowane w Javascript. Widać z niego, że typ zmiennej może się zmieniać dynamicznie. Jest to tak wane typowanie dynamiczne.

W najnowszym standardzie Javascript (ES2015) wprowadzono możliwość typowania statycznego (zmienna nie może zmieniać typu). Dodano także jeden typ danych: Symbol. Na razie jednak zajmujemy się standardem obsługiwanym wprost przez większość przeglądarek….

Typy proste i referencje

Ostatnie dwa typy danych w poprzednim przykładzie dotyczą obiektów. Zapis zmienna={} powoduje utworzenie pustego obiektu. Ważne jest aby odróżnić pusty obiekt i wartość null (pustą).

Przykład:

> var pusty_obiekt={};
> var pusta_ref=null;
> pusty_obiekt.opis='dynamicznie stworzona własność';
'dynamicznie stworzona własność'
> pusta_ref.opis='??';
TypeError: Cannot set property 'opis' of null
>

W przykładzie tym widać, że do pustego obiektu możemy dynamicznie dodawać własności. Wiąże się z tym bardzo istotna kwestia: pusta wartość (null) należy do tak zwanych typów prostych. Do takich typów należą:

  • boolean – wartość logiczna
  • number - liczba
  • string – łańcuch znaków
  • undefined – wartość nie zdefiniowana
  • null – wartość pusta
  • symbol - symbol wprowadzony w standardzie ES2015

Przeciwieństwem do nich jest typ obiektowy: object. Fundamentalna różnica polega na tym, że zmienne typu object nie zapamiętują wartości (obiektów), tylko referencje (wskaźniki) do nich.

Różnicę wyjaśnia poniższy przykład:

> var obiekt1={};
> var obiekt2;
> obiekt2=obiekt1;
{}
> obiekt1.wlasnosc=12;
12
> obiekt2.wlasnosc;
12
> var liczba1=0;
> var liczba2;
> liczba2=liczba1;
0
> liczba1=12;
12
> liczba2;
0
>

Widać, że zmienne obiekt1 i obiekt2 wskazują na ten sam obiekt, gdy tymczasem liczba1 i liczba2 to zupełnie odrębne byty. Jeśli chcemy użyć zmiennych prostych jako obiektów, następuje ich konwersja do typu obiektowego, ale w zmiennej nadal pamiętana jest wprost wartość (a nie referencja).

Konwersja typów

Stałe i zmienne typów prostych są w użyciu zamieniane automatycznie na obiekty. Jeśli w wyrażeniach występują dane różnych typów, następuje ich konwersja - tak, by wyrażenie mogło być wykonane. Kryje się w tym pewne niebezpieczeństwo - poieważ znak plus ('+') występuje zarówno w dodawaniu liczb jak i napisów - gdy nie ma jednoznaczności i Javascript przyjmuje, że chodzi o napisy!

> 2+2
4
> '2'+'2'
'22'
> 2+'2'
'22'
> 2+String('2')
'22'
> 2+Number('2')
4
> 2*'2'
4
> '2'/'2'
1
> true/String('2')
0.5
> (2).toString()
'2'

Ostatni przykład pokazuje, że rzeczywiście mamy do czynienia z obiektami i możemy wykorzystać ich własności. Opis tych własności możesz znaleźć na stronach:

Zamiast ujmować liczbę w nawiasy, można w miejsce kropki wpisać dwie kropki (chodzi o odróżnienie kropki dziesiętnej od kropki oznaczającej sięganie do środka obiektu:

> 2..toString()
'2'

Obiekty typu Number mają zdefiniowaną wartość NaN (Not a Number) - wskazującą na to, że to nie jest liczba

> 2 + undefined
NaN
>

Klasy i obiekty

W Javascript można zamiast o typach danych mówić o klasach tych danych - gdyż wszystkie zmienne i stałe są traktowane jak obiekty. Należy w tym miejscu zwrócić uwagę na różnicę między klasą a obiektem danej klasy. W tym drugim przypadku mówimy także o "instancjach" (wystąpieniach obiektu danej klasy). Niektóre metody operowania danymi są zdefiniowane dla klasy obiektów - i można ich użyć nawet gdy nie mamy żadnej instancji. Na przykład String.fromChaCode:

String.fromCharCode(65,66,67); // "ABC"

Ta funkcja zwraca łańcuch znaków na podstawie liczb oznaczających kody (Unicode - zgodne z ASCII) kolejnych liter.

Gdy tworzony jest obiekt danej klasy, wykorzystywany jest tak wany "prototyp". Obiekt otrzymuje wszystkie własności zdefiniowane w prototypie. Na przykład dla obiektów klasy string prototyp zawiera funkcję toUpperCase (zamiana na duże litery). Dla klasy String nie jest ona dostępna:

> ('błędy').toLocaleUpperCase();
'BŁĘDY'
> var msg='błędy'
> console.log(msg.toLocaleUpperCase());
BŁĘDY
> String.toLocaleUpperCase();
TypeError: String.toLocaleUpperCase is not a function

Wszystkie metody prototypu łańcuchów znaków znajdziesz na stronie: https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/String/prototype

Jedną z najciekawszych cech Javascript jest możiwość dodawania do prototypu własnych własności i metod. Nowo powstałe obiekty (instancje) danej klasy otrzymują tak dodane cechy:

> String.prototype.hash='#';
'#'
> var s1=String('abc')
> console.log(s1.hash);
#