Zmienne w JavaScript

Cześć! To jest fragment książki JavaScript od podstaw, która ma pomóc w nauce programowania od zera.

Poznaliśmy już kilka typów wartości oraz operacje, które można między nimi wykonywać. Możesz się zastanawiać, po co nam one. Po co mamy pisać "Witaj, " + "Michał", jeśli moglibyśmy od razu napisać "Witaj, Michał"? Wynika to z tego, że zazwyczaj różne części pochodzą z różnych miejsc. Na przykład powitanie mogłoby wyglądać "Witaj, " + userName, gdzie userName będzie wskazywało na imię, które użytkownik podał w czasie rejestracji. Tutaj userName to zmienna. Czyli co? Dowiesz się tego w tym rozdziale.

const i let

Istnieją dwa podstawowe sposoby tworzenia zmiennych we współczesnym JavaScript. Najczęściej używa się słówka const, a za nim nazwy zmiennej, znaku równości i wartości, na którą ta zmienna ma wskazywać.

Operator porównania === i operator przypisania = poza użyciem tego samego znaku równości nie mają ze sobą wiele wspólnego i nie powinny być mylone. === porównuje dwie wartości i zwraca true lub false. = przypisuje wartość do zmiennej.

Słówko const pochodzi od angielskiego słówka "constant", co oznacza "stały". Wynika to z tego, że przy deklaracji musimy określić wartość, a potem nie możemy już do niej przypisać żadnej innej wartości.

const userName = "Michał";
userName = "Marek"; // Błąd!
// Od tego miejsca kod nie będzie dalej działał!

Uwaga! Jak widzisz czerwony tekst w konsoli, informuje on o błędzie. Warto go przeczytać. W przypadku zmiennych częstym błędem jest "Identifier has already been declared", który występuje, gdy próbujemy ponownie zadeklarować tą samą stałą. Często wyświetla się, gdy ktoś kopiuje kolejne przykłady do konsoli, bez odświeżania strony.

Alternatywnym sposobem zdefiniowania zmiennej jest użycie słówka let zamiast const. Cała reszta definicji oraz jej użycie są identyczne. Różnica polega jednak na tym, że do takiej zmiennej można później przypisać inną wartość.

let userName = "Michał";
console.log("Witaj, " + userName); // Witaj, Michał

userName = "Marek";
console.log("Witaj, " + userName); // Witaj, Marek

Nomenklaturowo, zarówno przy użyciu słówka let jak i const, definiujemy zmienną. Wydaje się to nieintuicyjne, ponieważ słówko "zmienna" sugeruje zmianę, a przecież jak użyjemy const, to nie możemy zmienić, na co ta zmienna wskazuje. Nazewnictwo wynika jednak z ewolucji języków programowania.

Może się wydawać, że skoro let zawiera wszystkie cechy const, a do tego można ją zmienić, najłatwiej byłoby jej zawsze używać. W praktyce jednak znacznie częściej używamy const. Dzięki temu, że nie można przypisać do niej niczego nowego, łatwiej jest zapamiętać co stoi za daną zmienną, a w rezultacie wnioskować na temat działania kodu. Należy ich więc używać świadomie - jeśli wartość jest stała, używać słówka const, a jeśli planujemy, że będzie się ona zmieniać, używać słówka let.

Czasem możesz spotkać się również ze słówkiem var. Współcześnie zastępuje się je przez let, który jest jego następcą. Także w pewnych okolicznościach da się zupełnie pominąć słowo kluczowe typu let, var czy const. To jednak uważa się za bardzo złą praktykę i stanowczo tego odradzam.

Ćwiczenie: Definiowanie zmiennych

Uzupełnij brakujące fragmenty:

____ constantValue = "1234";
console.____(constantValue); // 1234

____ name = _______;

//***
console.log(name); // Michał
name = "Marcin";
console.log(name); // ______

Odpowiedzi na końcu książki.

Nazywanie zmiennych

Przy nazywaniu zmiennych możemy wykorzystywać małe i duże znaki, cyfry, znak podkreślenia (_$) oraz dolara ($). Przyjęła się jednak następująca konwencja:

  • zaczynamy od małych liter, a wielkich używamy tylko wtedy, gdy zaczynamy kolejne słowa (ta notacja znana jest jako lower-camelcase),
  • używamy nazw anglojęzycznych (czasem robimy wyjątki dla nazw własnych),
  • nie można zacząć nazwy zmiennej od cyfry, zwyczajowo raczej umieszczamy je na ostatnich pozycjach.

Gdy nazywamy zmienną, na początek polecam:

  1. zastanowić się na co będzie ona wskazywała (załóżmy, że potrzebujemy zmiennej przechowującej adres zdjęcia użytkownika),
  2. wyrazić to możliwie krótko w języku angielskim (w naszym przykładzie mogłoby to być "user image url"),
  3. zapisać to w notacji camelcase (w naszym przykładzie "userImageUrl").

Oto kilka przykładów poprawnie nazwanych zmiennych:

  • userName
  • isTeaTime
  • userGroupKey
  • user1, user2

A oto kilka przykładów nie najlepiej nazwanych zmiennych:

  • bookscollection - jest niepoprawne, ponieważ collection to osobne słowo i powinno być wielką literą (lepsza wersja to booksCollection),
  • 1book - jest niepoprawne, ponieważ liczba nie może się znajdować na pierwszej pozycji (lepsza wersja to oneBook),
  • listaKsiążek - jest niepoprawne, ponieważ powinniśmy nazywać zmienne po angielsku (lepsza wersja to booksList).

W kolejnych częściach książki zobaczysz jeszcze wiele przykładów poprawnie nazwanych zmiennych. Zwróć na nie uwagę.

Ćwiczenie: Nazywanie zmiennych

Jak myślisz, które z poniższych zmiennych mają dobre nazwy?

  • publicWorkshops
  • 1wayTicket
  • arbitraryUser
  • noteType
  • userMaciek
  • postUserRequest
  • szkolenieWarszawa

Odpowiedzi na końcu książki.

Przypisanie rozszerzające wartość zmiennej

W programowaniu częstym wzorcem jest sytuacja, gdy zamiast całkowitej modyfikacji wartości zmiennej, jedynie coś do niej dodajemy lub odejmujemy. Dla przykładu: moglibyśmy dopisywać kolejne produkty do listy zakupów albo dodać nową wartość do sumy.

Aby dodać coś do już istniejącej zmiennej, wystarczy ustawić ją na sumę wartości aktualnej i tej, którą chcemy dodać.

let cartList = "";

cartList = cartList + "Jabłko, ";
// "" + "Jabłko, " daje "Jabłko, "
console.log(cartList); // "Jabłko, "

cartList = cartList + "Gruszka, ";
// "Jabłko, " + "Gruszka, " daje "Jabłko, Gruszka, "
console.log(cartList); // "Jabłko, Gruszka, "

cartList = cartList + "Pomidor";
// "Jabłko, Gruszka, " + "Pomidor" daje
// "Jabłko, Gruszka, Pomidor"
console.log(cartList); // "Jabłko, Gruszka, Pomidor"

let sum = 0;

sum = sum + 1; // 0 + 1 daje 1
console.log(sum); // 1

sum = sum + 2; // 1 + 2 daje 3
console.log(sum); // 3

sum = sum + 3; // 3 + 3 daje 6
console.log(sum); // 6

Ponieważ taki sposób modyfikowania wartości jest bardzo popularny, powstał skrócony zapis. Zamiast pisać variable = variable + toAdd, możemy użyć operatora += i napisać variable += toAdd.

let cartList = "";

cartList += "Jabłko, ";
// "" + "Jabłko, " daje "Jabłko, "
console.log(cartList); // "Jabłko, "

cartList += "Gruszka, ";
// "Jabłko, " + "Gruszka, " daje "Jabłko, Gruszka, "
console.log(cartList); // "Jabłko, Gruszka, "

cartList += "Pomidor";
// "Jabłko, Gruszka, " + "Pomidor" daje
// "Jabłko, Gruszka, Pomidor"
console.log(cartList); // "Jabłko, Gruszka, Pomidor"

let sum = 0;

sum += 1;
console.log(sum); // 1

sum += 2;
console.log(sum); // 3

sum += 3;
console.log(sum); // 6

W przypadku liczb przydatne jest również odejmowanie wartości. Tutaj pomaga operator -=. Użycie variable -= toSubtract jest ekwiwalentem variable = variable - toSubtract.

let num = 10;

num -= 1;
console.log(num); // 9

num -= 2;
console.log(num); // 7

num -= 3;
console.log(num); // 4

Inne operacje matematyczne również można tak skrócić. Zamiast x = x * y, piszemy x *= y. Zamiast x = x % y, piszemy x %= y itp.

Ćwiczenie: Dodawanie i odejmowanie od wartości zmiennych

Uzupełnij brakujące fragmenty:

___ fruits = "Figa ";
___ price = 0;

fruits __ "Gruszka ";
price __ 3.2;

console.log(fruits); // Figa Gruszka
console.log(price); // 3.2

fruits += ________;
price += ____;

console.log(fruits); // Figa Gruszka Banan
console.log(price); // 6

// Stosujemy kupon zniżkowy
price ___ 1.4;

console.log(price); // 4.6

Odpowiedzi na końcu książki.

Zmienne wskazują na wartości

Zmienna przypomina kartkę z numerem schowka, w którym znajduje się wartość. Gdy interpreter widzi wyrażenie "Witaj, " + userName, to chciałby po obu stronach plusa mieć wartości, ale zamiast jednej z nich znajduje zmienną. Ta zmienna zawiera w sobie adres, pod którym poszukiwana wartość się znajduje. Interpreter więc sięga tam i znajduje poszukiwaną nazwę użytkownika. Dlatego mówię, że zmienne nie zawierają wartości, a raczej na nie wskazują.

Załóżmy, że kiedy pytamy o wartość userName, ta wskazuje na "Michał". Kiedy zmienimy by wskazywała na "Marcin", to poprzednia wartość jest zapominana. Gdy wówczas zapytamy o wartość userName, dostaniemy wartość, na którą aktualnie ona wskazuje, czyli "Marcin".

let userName = "Michał";
console.log(userName); // Michał

userName = "Marcin";
console.log(userName); // Marcin

Ta subtelna metafora pomaga w bardziej skomplikowanych zastosowaniach zmiennych. Co zrobić w sytuacji, gdy do zmiennej przypiszemy wartość innej zmiennej? Warto pamiętać, że zmienne wskazują na wartości, a nie na inne zmienne. Poniższy problem często myli nawet doświadczonych programistów, co bywa źródłem poważnych błędów w aplikacjach. Stanie się to jednak jasne, gdy pojmiemy metaforę wskazywania na wartości, która wiernie oddaje, jak naprawdę działają zmienne.

let a = 10;
let b = a;
a = 20;
console.log(b); // 10,
// ponieważ b wskazuje na wartość 10, a nie na zmienną
console.log(a); // 20

Przedstawiony tutaj obraz nieco się skomplikuje, gdy wprowadzimy obiekty. Będzie to omówione w dalszej części.

Zmienne niezdefiniowane i wartość undefined

Najczęściej określamy, na co wskazuje zmienna przy definicji, poprzez postawienie znaku równości i podanie jakiejś wartości.

let name = "Michał";
console.log(name); // Michał

Czasem jednak tworzymy zmienną bez wartości, by określić ją później.

let name;
name = "Michał";
console.log(name); // Michał

Co jednak, gdy zapytamy o wartość zmiennej, która nie miała jeszcze szansy dostać wartości? W takim przypadku otrzymamy wartość specjalną undefined.

let name;
console.log(name); // undefined

Do tej wartości można się odnosić przy użyciu słówka undefined. Przykładowo, możemy ją ustawić jako wartość zmiennej. Robi się tak, by pozbyć się wartości zmiennej.

let name = undefined; // równoznaczne z: let name
console.log(name); // undefined

name = "Marcin";
console.log(name); // Marcin

name = undefined;
console.log(name); // undefined

Możemy też użyć jej do sprawdzenia, czy wartość została ustalona. Wtedy postawimy ją po prawej stronie znaku !==. Aby sprawdzić, czy jest nieustalona, porównujemy natomiast przy użyciu ===.

let name;
console.log(name !== undefined); // false
console.log(name === undefined); // true

name = "Marcin";
console.log(name !== undefined); // true
console.log(name === undefined); // false

name = undefined;
console.log(name !== undefined); // false
console.log(name === undefined); // true

Od porównywania z undefined, za bezpieczniejsze uważa się sprawdzenie, czy typ tej zmiennej jest "undefined". Takie sprawdzenie wykryje zarówno czy zmienna ma określoną wartość, jak i czy została zdefiniowana. Jeśli nie mamy więc pewności czy zmienna istnieje, sprawdzamy to poprzez porównanie jej typu.

let firstName
console.log(typeof firstName === "undefined"); // true
console.log(firstName === undefined); // true

// lastName nigdy nie została zdefiniowana
console.log(typeof lastName === "undefined"); // true
console.log(lastName === undefined); // Błąd!
// ReferenceError: lastName is not defined

Wartość null

Bardzo podobną wartością jest null. Zwykle ustawiamy ją, gdy chcemy zakomunikować, że jakiejś wartości brakuje. null ma podobne, ale jednak nieco inne znaczenie od undefined. Jeśli sprawdzamy wartość zmiennej name i jest ona undefined, to zwykle interpretuje się to tak, że nie została ona jeszcze określona. Jeśli natomiast byłaby ona równa null, oznaczałoby to raczej, że świadomie ustawiony został znacznik braku wartości. Być może użytkownik wybrał, że nie chce podawać swojego imienia. Poza tym wartości te zachowują się właściwie tak samo. Nie są jednak równe, gdy porównujemy je poprzez ===.

let name = null;
console.log(name); // null
console.log(name === null); // true
console.log(name === undefined); // false

name = "Marcin";
console.log(name); // Marcin
console.log(name === null); // false

name = null;
console.log(name); // null
console.log(name === null); // true

Te wartości jeszcze przydadzą się nam w następnych rozdziałach. Porównując to do nauki języka obcego, są to słówka, które teraz trzeba sobie przyswoić, aby potem je rozumieć w bardziej skomplikowanych zdaniach.

Zmienne są bardzo ważnym krokiem ku zrozumieniu programów napisanych w JavaScript. Razem z funkcjami, stanowią podstawę współczesnych projektów programistycznych. Będziemy je widzieli nieustannie, na każdym etapie naszej przygody.

Ćwiczenie: undefined i null

Uzupełnij brakujące fragmenty:

let name = ____;
let surname;

console.log(name); // null
console.log(surname); // ______

name = surname;
surname = "Michalski";

console.log(name); // ______
console.log(surname); // ________

Odpowiedzi na końcu książki.