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 zwracatrue
lubfalse
.=
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 iconst
, definiujemy zmienną. Wydaje się to nieintuicyjne, ponieważ słówko "zmienna" sugeruje zmianę, a przecież jak użyjemyconst
, 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 przezlet
, który jest jego następcą. Także w pewnych okolicznościach da się zupełnie pominąć słowo kluczowe typulet
,var
czyconst
. 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:
- zastanowić się na co będzie ona wskazywała (załóżmy, że potrzebujemy zmiennej przechowującej adres zdjęcia użytkownika),
- wyrazić to możliwie krótko w języku angielskim (w naszym przykładzie mogłoby to być "user image url"),
- 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 tobooksCollection
),1book
- jest niepoprawne, ponieważ liczba nie może się znajdować na pierwszej pozycji (lepsza wersja tooneBook
),listaKsiążek
- jest niepoprawne, ponieważ powinniśmy nazywać zmienne po angielsku (lepsza wersja tobooksList
).
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.