Podstawowe typy zmiennych

W standardzie ECMA Script występuje siedem typów zmiennych:  null, undefined, object, boolean, string, number i nowy, wprowadzony w ECMA Script 6 typ Symbol. Jeśli dopiero zaczynasz przygodę z językiem JavaScript możesz zapytać – „A co z tablicami, czy na powyższej liście nie brakuje czasem typu Array?”. W artykule omawiam krótko każdy z siedmiu podstawowych typów zmiennych i wyjaśniam, co się stało z „zagubionym” typem Array…

Na wstępie należy odpowiedzieć sobie na pytanie czym właściwie jest typ zmiennej w języku JavaScript? Otóż JS to język nie mający ścisłej kontroli typu zmiennych, co przez wielu programistów jest uważane za wadę (dotyczy to głównie programistów języków C, Java i innych z tzw. silnym typowaniem). Nie będziemy się tutaj jednak zastanawiać nad wadami i zaletami słabej kontroli typów – tak po prostu jest w JavaScript i tego nie zmienimy…

Słaba typizacja zmiennych w JavaScript umożliwia dynamiczną zmianę typu nie tyle samej zmiennej, co jej wartości. Jednym z przykładów stosowanych w praktyce jest dynamiczne „przechodzenie” pomiędzy ciągami znakowymi, liczbami i tablicami.

Poniżej pokazano omawiane zagadnienie na przykładzie zmiennej v, której przypisujemy wartość liczbową. Naszym zadaniem jest zadeklarowanie drugiej zmiennej „r”, która będzie przechowywała również wartość typu number, ale będzie to liczba „v” z odwrotną kolejnością cyfr.

var v = 12345; //zadeklarowanie zmiennej liczbowej
typeof v === 'number'; //true

var r = parseInt(v.toString().split('').reverse().join(''));
r; //54321
typeof r === 'number'; //true

Omówmy krótko w jaki sposób powstaje wartość zmiennej „r”:

  1. W pierwszym kroku na zmiennej v (będącej typem number) wywołujemy metodę toString(), która konwertuje ją do wartości typu string (ciągu znakowego).
  2. W kolejnym kroku na zmiennej typu string wywołujemy metodę split(”), która powoduje utworzenie z niej tablicy.
  3. Tablice posiadają metodę reverse, która zamienia kolejność elementów.
  4. Następnie metoda join(”) powoduje ponowną konwersję do typu string, poprzez połączenie kolejnych elementów tablicy.
  5. Na koniec wywołana zostanie metoda globalna parseInt(), która zmieni naszą liczbę z typu string na typ number (jest to bardzo duże uproszczenie nie do końca zgodne z tym do czego faktycznie służy ta metoda, ale na razie pozostawmy ten temat na późniejsze rozważania).

Jak zatem widać JavaScript pozwala na dynamiczną zmianę typu wartości co w praktyce daje duże możliwości operowania na zmiennych. Omówmy zatem najważniejsze cechy typów zmiennych w ECMA Script.

Ciągi znakowe – zmienne typu String

Wartości łańcuchowe typu string przypisuje się przy użyciu cudzysłowów lub apostrofów.  W JavaScript nie ma znaczenia, który z poniższych zapisów zastosujemy – w obu przypadkach stworzymy zmienną z wartością typu łańcuchowego String:

var s1 = "text",
    s2 = 'text';
s1 === s2; //true

Zmienne typu string mogą przechowywać łańcuchy praktycznie dowolnej długości, stworzone ze znaków Unicode (16-bitowy uniwersalny format zapisu znaków). Oznacza to, że ciągi znakowe nie muszą składać się wyłącznie ze „standardowych” znaków alfanumerycznych, lecz mogą zawierać również inne znaki, jak np. symbol nut muzycznych: „♫”. Aby stworzyć taki znak i zapisać go jako wartość zmiennej wpisz w konsoli:

var s = '\u266b';

Znaki w formacie Unicode tworzy się poprzez zapis ‚\uXXXX’, gdzie XXXX oznacza czterocyfrowy numer znaku w zapisie szesnastkowym. Dla znaków reprezentowanych przez dwuznakową lczbę szesnastkową można stosować zapis skrócony:

var s1 = "\u0040", //symbol @
    s2 = "\x40"; //symbol @;
s1 === s2; //true

W ciągach łańcuchowych każdy znak ma przypisany indeks, rozpoczynający się od zera. Umożliwia to szybki dostęp do dowolnego znaku ciągu poprzez odwołania podobne do odczytu danych tablicowych. Należy jednak uważać na taki sposób operowania na ciągach znakowych gdy stosujemy zapisy znaków Unicode w formacie \u lub \x.

var s1 = 'text',
    s2 = "\u0040";

s1[0]; //"t"
s1[1]; //"e"

s2[0]; "@"
s2[1]; //undefined

Zmienne liczbowe – typ Number

W JavaScript występuje tylko jeden typ liczbowy – Number. Przechowuje on zarówno liczby całkowite jak i zmiennoprzecinkowe. Liczby całkowite są tutaj traktowane nieco inaczej niż często spotykany w innych językach programowania typ integer. W JavaScript liczby 20 i 20.00 są sobie równe, to znaczy:

var a = 20,
    b = 20.00;
a === b; //true

Liczby w JavaScript zapisywane są w formacie zgodnym ze standardem IEEE 754, a więc z formacie 64-bitowym (określanym często jako format podwójnej precyzji).  W ECMA Script 6 wprowadzono jednak pewne ograniczenia związane z tzw. bezpiecznym zakresem liczb całkowitych i określone zostały granice, czyli maksymalne wartości typu number. Liczba całkowita nie może być większa niż (2^53-1) co jest reprezentowane przez stałą Math.MAX_SAFE_INTEGER. Istnieje także analogicznie Math.MIN_SAFE_INTEGER. Jest to jednak na tyle szeroki zakres, że w większości przypadków w zupełności wystarczy (problemy występują głównie tylko przy bardziej skomplikowanych algorytmach matematycznych).

Obiekty i tablice

Język JavaScript jest dość nietypowy w porównaniu do języków takich jak C, Java, PHP itp. Tutaj praktycznie wszystko jest obiektem, więc nie można mówić  programowaniu strukturalnym i obiektowym (co jest przedmiotem wielu dyskusji np. w odniesieniu do PHP).

Obiekty stanowią pewnego rodzaju fundament JavaScript. Powyższe typy String i Number tak na prawdę również są obiektami. Ciąg znakowy możemy zadeklarować na dwa sposoby:

var s1 = "ahoj",
    s2 = String("ahoj");
s1 === s2; //true

W przypadku zmiennej s2 w sposób jawny tworzymy obiekt typu String, natomiast w zmiennej s1 proces ten jest realizowany wewnętrznie przez silnik JavaScript. Jest to jednak pewne uogólnienie, gdyż w rzeczywistości obie deklaracje zmiennych różni kilka kwestii, ale do tego powrócimy w kolejnych artykułach. Na razie proponuję, abyś zmienne deklarował przy użyciu tzw. zapisów literałowych, czyli bez jawnego stosowania zapisu String(), Number(), Boolean(). Wyjątkiem od tej zasady jest typ Symbol, dla którego nie ma skróconego zapisu literałowego.

W JavaScript obiekty zawierają wiele różnych właściwości, przy czym właściwości które można wywołać nazywane są funkcjami. Poniżej znajduje się deklaracja (z użyciem literału {…}) prostego obiektu:

var obj = {
        a: "first", //przecinek po deklaracji każdej właściwości
        b: "second",
        c: function () {};
    }; //pamiętaj o średniku kończącym instrukcję var

Jest to tylko jedna z możliwości stworzenia nowego obiektu w JavaScript. Inne metody zostaną opisane w oddzielnym artykule, w tym m.in. skrócone zapisy ECMA Script 6 czy tworzenie obiektów „całkowicie pustych”.

No dobrze, ale co z tablicami? Otóż w przeciwieństwie do języka PHP tutaj nie występują tzw. tablice asocjacyjne, czyli takie, w których indeksami są ciągi znakowe. W JavaScript w zasadzie nie ma oddzielnego typu Array. Tablice są obiektami z własnym konstruktorem, które posiadają pewne specyficzne właściwości. Tablice w JavaScript mają zawsze indeksy będące liczbami całkowitymi (zaczynającymi się od zera).

Tablicę asocjacyjną można w pewnym stopniu zasymulować tworząc obiekt z użyciem literałów { … }. Nie są to jednak takie same elementy jak tablice asocjacyjne w PHP, gdyż w JavaScript nie zawsze możemy być pewni kolejności, w jakiej interpreter będzie przetwarzał kolejne właściwości obiektu.

Jeśli jednak interesują nas wyłącznie wartości, a indeksy numerujemy liczbowo to możemy użyć literału tablicowego:

var arr = [1,2,3,4,5];
typeof arr; //"object"
Object.prototype.toString.apply(arr); //"[object Array]"

Typ Undefined, Null, Boolean

Null i undefined to dwa typy specjalne. Typ undefined możemy w sposób jawny przypisać do zmiennej, lecz znacznie częściej spotkamy się z sytuacja, że w pewnym sensie zrobi to za nas silnik JavaScript. Otóż typ undefined określa zmienne, które zostały zadeklarowane, ale nie przypisano im żadnej wartości. Brzmi to pewnie dość skomplikowanie, dlatego najlepiej od razu przejdźmy do przykładu:

var a = undefined,
    b;
a; //undefined
b; //undefined
c; //ReferenceError - zmienna nie istnieje!

Jak widać undefined odnosi się wyłącznie do zmiennych, które zostały zadeklarowane słowem var lub let. Wyjątkiem jest słowo const, które wymaga jawnego przypisania wartości:

var a; //undefined
let b; //undefined
const c; //SyntaxError - brak deklaracji zmiennej c
const c = undefined; //undefined

Typ null oznacza pustą wartość lecz nie jest to tożsame z undefined (które określa brak wartości). Należy jednak uważać na pewien niuans specyficzny dla JavaScript, a mianowicie traktowanie zmiennej z wartością null jako obiektu (który nie ma żadnych właściwości):

var a = null,
    b = undefined;
typeof a; //"object"
typeof b; //"undefined"

Istnieje jeszcze kilka innych problemów związanych ze zmiennymi undefined i null ale zajmiemy się tym w oddzielnych wpisach.

Ostatnim z typów specjalnych (obecnym praktycznie w każdym języku programowania) jest Boolean, określający tzw. prawdę lub fałsz (true / false). Zmienne te są deklarowane w sposób bezpośredni:

var a = true, b = false;
typeof a; //"boolean"
typeof b; //"boolean"

Nowy typ ECMA Script 6: Symbol

Zmienną typu Symbol deklaruje się wyłącznie przy użyciu zapisu Symbol(‚nazwa’); Nie występuje tutaj skrócona forma literałowa. Istnieje co najmniej kilka przypadków gdzie symbole znajdą swoje zastosowanie, np. w iteratorach lub w celu stosowania nazw właściwości lub stałych, których nie dałoby się zadeklarować w sposób „tradycyjny” ze względu na niepopraną nazwę. Symbolu można zatem użyć do zadeklarowania zmiennej przechowującej nazwę właściwości, zdarzenia DOM itp.:

const MY_PARAM = Symbol("myObj.myParam");

Dużą zaletą symboli jest fakt, że nie można ich w żaden sposób powielić (celowo lub przypadkowo), a ponad to istnieje globalny rejestr symboli. Ponad to symbole są wykorzystywane również w tzw. iteratorach, które również stanowią nowość wprowadzoną w standardzie ECMA Script 6.

Dodaj komentarz

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