Zmienne i stałe
Zmienne to coś w rodzaju "pudełek", w których pod nazwami możemy przechowywać różne rzeczy takie jak liczby, teksty, obiekty itp.
Deklarowanie zmiennych
Aby zadeklarować zmienną, powinniśmy posłużyć się jednym ze słów kluczowych. Do stworzenia zmiennej w JavaScript przez lata używało się słowa kluczowego var:
var txt = "Ala ma kota";
var nr = 20;
var url = "kontakt.html";
console.log(txt);
console.log(nr);
console.log(url);JavaScript ewoluuje. W 2015 roku pojawiła się ECMAScript 2015 wprowadzając sposoby deklaracji zmiennych za pomocą słów let i const. Słowo let oznacza zmienną, natomiast const stałą:
let txt = "Przykładowy tekst"; //zmienna
txt = "Inny tekst"; //zmieniamy wartość
const nr = 102; //stała
nr = 103; //błąd - nie można przypisać nowej wartościW dzisiejszych czasach mimo tego, że w internecie spotkamy miliony skryptów wykorzystujących var, zaleca się stosować const i let. Dzięki nim nasze skrypty nie tylko działają lepiej pod względem zarządzania pamięcią, ale i potencjalnie unikamy niektórych problematycznych sytuacji, które występowały przy var (a o których dowiesz się w dalszej części kursu).
Przeglądając Internet zapewne natrafisz na wiele przykładów skryptów, gdzie autorzy tworzą zmienne z pominięciem słów kluczowych var/let/const np:
nr = 200;
console.log(nr); //200
for (i=0; i<100; i++) {
...
}
for (el of array) {
...
}Nie rób tak. Tworząc zmienne nie pomijaj słów let/const/var. W kolejnych rozdziałach dowiesz się czemu.
Po co stosować zmienne?
Po co w ogóle stosować zmienne? Rozpatrzmy prosty przykład dodawania liczb:
console.log(6 + 5 + 1);
console.log(4 + 5 + 2);
console.log(1 * 5 + 5 - 2);
console.log(8 + (5 * 10) + 5 + 9 + (5 * 10) + 5);
...
...Przypuśćmy, że teraz chcielibyśmy zmienić cyfrę 5 w każdym równaniu.
Dla tak małego skryptu zmiana tej cyfry nie jest wielkim problemem. Co by się jednak stało gdybyśmy takich równań w naszym przykładzie mieli na przykład tysiąc lub nawet sto tysięcy? I tu właśnie przychodzą nam z pomocą zmienne:
const nr = 4;
console.log(6 + nr + 1);
console.log(4 + nr + 2);
console.log(1 * nr + nr - 2);
console.log(7 + (nr * 10) + nr + 9 + (nr * 10) + nr);Pod zmienne możemy podstawiać nie tylko liczby, ale teksty, funkcje, obiekty, tablice - czyli dowolne rzeczy, na których będziemy pracować w naszych kodach:
const min = 5;
const max = 15;
//dzięki zmiennym poprawia mi się czytelność kodu i łatwiej go zmieniać
const random = Math.floor(Math.random()*(max-min+1)+min);
console.log(random);//pod zmienną wstawiam pobrany ze strony element
const btn = document.querySelector(".button");
//i zaczynam na niej działać
btn.classList.add("btn-primary");
btn.setAttribute("title", "Kliknij mnie");
btn.innerText = "Kliknij mnie!"Nazewnictwo zmiennych
Nazwy zmiennych i stałych które deklarujemy nie mogą być byle jakie. Istnieją pewne zasady których musimy się trzymać. I tak:
wielkość liter ma znaczenie. Zmienna myTXT to nie to samo co mytxt
nazwa zmiennej nie może zaczynać się od cyfry,
nazwa zmiennej nie może zawierać spacji, kropki, przecinka ani myślnika (można natomiast używać podkreślenia),
nazwą zmiennej nie może być słowo kluczowe zarezerwowane przez JavaScript
Po prostu nie zaczynaj nazw od cyfr i pisz nazwy zmiennych po angielsku. Bardzo częstą praktyką jest stosowanie zapisu camelCase, czyli np. veryImportantThing, ale wiele osób stosuje też zapis z podłogą czyli very_important_thing.
Jest jednak ważniejsza sprawa, którą zapamiętaj. Nazywaj swoje zmienne tak, by dało się zrozumieć do czego się odnoszą. Zmienna o nazwie elementsCount jest bardziej czytelna, niż xxx. W tym kursie czasami będę korzystał z mało czytelnych zmiennych (np. a), ale wynika to tylko z tego, że kod często jest bardzo, bardzo krótki, a i jestem leniem.
Dla ciekawskich - nazwy zmiennych mogą być bardzo różne. Nie jest to oczywiście zalecane i trzeba to traktować jako ciekawostkę.
//dobre nazwy
const myAge = 10;
const my_age = 10;
//błędne nazwy
const my-age = 10;
const 2myAge = 10;
const my age = 10;
const mójWiek = 10;const
Jedną z głównych bolączek var od zawsze było to, że za pomocą tego słowa można tworzyć tylko zmienne. Oznacza to, że w każdym momencie mogę później taką zmienną zmienić:
var key = "21389123718398";
...
key = 20;W celu uniknięcia błędów część programistów nazywało stałe dużymi literami. Dzięki temu osoba pisząca kod wiedziała czy powinna czy nie powinna zmieniać danej zmiennej.
var KEY = "21389123718398";...konwencja ta jest nadal przez wielu stosowana - co jest akurat bardzo spoko, ponieważ po samej nazwie zmiennej nie sposób wykryć czy można zmienić jej wartość.
Wraz z wprowadzeniem nowych słów let/const dostaliśmy rozróżnienie na zmienne i stałe. Zmienne deklarowane za pomocą let/var można w przyszłości zmienić - czyli podstawić im nową wartość. Zmiennym stworzonym za pomocą const nie jesteśmy w stanie podstawić nowej wartości.
var text = "ala";
text = "ala ma kota"; // wszystko ok, bo var to zmienna
let a = 0;
a = 10; //wszystko ok, bo let
const b = 0;
b = 10; //błąd - do stałej nie możemy przypisać nowej wartości
const name = "Ala";
name = "Monika"; //błądJeżeli jednak pod daną stałą const podstawimy jakiś obiekt, bez problemu będziemy mogli zmieniać jego właściwości:
const tab = [1,2,3]; //tablica to też obiekt
tab[3] = 4;
tab.push(5, 6);
console.log(tab); //[1, 2, 3, 4, 5, 6]
tab = [1, 2, 3, 4, 5, 6]; //błąd - podstawiłem zupełnie nową tablicę
const user = {
name: "Piotr",
age: 18
}
user.age = 20;
user = { //błąd - bo podstawiłem totalnie nowy obiekt
name: "Piotr"
}Różnice między var a let/const
Deklaracje let/const nie tylko wprowadziły stałe, ale także kilka różnic w stosunku do var.
Pierwsza i najważniejsza różnica między let/const a var to zasięg zmiennych.
W przypadku let/const zmienne mają zasięg blokowy, co w skrócie oznacza "od klamry do klamry":
let a = 20; //zmienna globalna
{
let a = 30; //zmienna lokalna
console.log(a); //30
}
console.log(a); //20{
let a = "Ala";
console.log(a); //Ala
}
{
console.log(a); //error - nie ma takiej zmiennej
}
{
let a = "Ola"; //zmienna lokalna w tym bloku
console.log(a); //Ola
}
console.log(a); //error: a is not definedfor (let i=0; i<10; i++) {
console.log(i);
}
console.log(i); //error: i is not defined{
let nr = 102;
console.log(nr); //102
}
{
console.log(nr); //błąd: nr is not defined
}
console.log(nr); //błąd: nr is not definedZmienne deklarowane za pomocą var mają natomiast zasięg funkcyjny, czyli ich zasięg określa ciało funkcji.
var a = 20; //zmienna globalna
function test() {
var a = 30; //zmienna lokalna
console.log(a); //30
}
test();
console.log(a); //20W nielicznych sytuacjach może to powodować niezamierzone działanie kodu.
if (true) {
var myVar = 20;
}
console.log(myVar); //20for (var i=0; i<10; i++) {
console.log(i);
}
console.log(i); //10W kolejnych rozdziałach natrafisz na przykłady bardziej praktyczne...
Kolejna cecha rozróżniająca var od let/const jest taka, że zmienne var możemy ponownie deklarować, co jest niemożliwe w przypadku let i const:
var name = "Marcin";
var name = "Karol";
console.log(name); //Karollet name = "Marcin";
let name = "Karol"; //błąd = Identifier "name" has already been declared
console.log(name);W przypadku const/let musimy stosować inne bloki:
{
let name = "Marcin";
console.log(name);
}
{
let name = "Karol";
console.log(name);
}Kolejna różnica między starszą deklaracją var a jej młodszymi braćmi to tak zwany hoisting (windowanie). JavaScript lubi pomagać programiście. Jednym z takich przypadków pomocy jest niewidoczne dla programisty wynoszenie deklaracji "na początek kodu" (w pierwszym momencie twój kod czytany jest przez silnik Javascript (jest parsowany), a następnie tworzony jest specjalny "kontekst wykonawczy", czyli miejsce w pamięci, gdzie zawarte są wszystkie zmienne i funkcje używane przez ciebie - bardzo dobrze opisuje to film https://www.youtube.com/watch?v=Fd9VaW0M7K4).
W przypadku var odwołanie się do zmiennej przed jej stworzeniem nie rzuci nam błędem, natomiast pokaże undefined:
var a; //niewidocznie przenoszona jest sama deklaracja - bez wartości
console.log(a); //undefined
var a = 200;Deklaracja zmiennej bez wartości wynoszona jest automatycznie na początek danego kodu (a w zasadzie na początek danego zakresu - np. na początek danej funkcji), w wyniku czego nasz powyższy skrypt w momencie wykonywania ma postać:
var a; //js przeniósł tutaj deklarację zmiennej ale bez jej wartości!
console.log(a); //wypisze undefined, ale błędu nie ma
var a = 20;Niektórzy programiści - szczególnie ci, którzy na co dzień używali innych języków, w których takie zjawisko nie występuje - dla uniknięcia takich niejawnych (a i niewidocznych dla nas) zachowań - stosowali konwencję deklaracji każdej zmiennej na początku kontekstu:
var text, age; //jeżeli nie podstawiamy wartości to równe są undefined
age = 20;
text = "Ala ma " + age + " lat";W przypadku let/const (ale też class) hoisting także istnieje, ale nie jesteśmy w stanie używać zmiennych przed ich zadeklarowaniem:
console.log(a); //Error: Cannot access "a" before initialization
let a = 20;To samo będzie się tyczyło wyrażeń funkcyjnych, czyli sytuacji, gdzie funkcję podstawiamy pod zmienną. Znowu - nie możemy użyć zmiennej przed jej stworzeniem:
myFn(); //Error: Cannot access "myFn" before initialization
const myFn = function() {
console.log("Lubie koty i psy");
}Ale o tym porozmawiamy sobie w rozdziale o funkcjach.
Miejsce przed deklaracją zmiennej let/const zwie się temporal dead zone, bo nie możemy odwoływać się do zmiennej, której jeszcze nie zadeklarowaliśmy. Dzięki takiemu zabiegowi nasz kod staje się bardziej logiczny - najpierw tworzymy wszystkie klocki (zmienne, funkcje), a dopiero potem ich używamy.
Ostatnią różnicą - dość mało znaną - jest to, że deklarując zmienną globalną var (poza ciałem funkcji), dodawana jest ona jako właściwość obiektu window. W przypadku let nic takiego się nie dzieje:
var a = 20;
let b = 30;
console.log(window.a); //20
console.log(window.b); //undefinedGdy wypiszemy sobie w konsoli obiekt window, pokaże nam się masa różnych rzeczy, które możemy (i zapewne będziemy) używać:
console.log(window);
Tworząc w powyższy sposób globalne zmienne var, moglibyśmy przez przypadek nadpisać niektóre funkcjonalności, które w przyszłości chcielibyśmy użyć:
var alert = "Tekst informacji";
var fetch = "Pobieram dane";
alert("Wypełnij te pola"); //błąd
fetch("https://jsonplaceholder.typicode.com/") //błądPrzy czym nie powinienem tutaj demonizować. Jeżeli piszesz swoje skrypty cokolwiek ponad 0 poziom wtajemniczenia, to raczej nie powinieneś nigdy natrafić na takie błędy. Ale któż wie...
To jak jesteśmy przy głupotach JS (o czym można by niezły art napisać), to jedną z kolejnych rzeczy jest fakt, że dla każdego elementu z ID tworzona jest zmienna o takiej samej nazwie, która wskazuje na dany element:
//nie stworzyłem nigdzie takiej zmiennej ale mam do niej dostęp
//bo na tej stronie jest element #mainContent (główna treść)
console.log(mainContent);W odczuciu autora tego kursu jest to złe, ponieważ dostajemy zmienne, które powstają z nieba. Jeżeli będziemy pracować na elementach z ID, mimo że JavaScript stworzył dla nich zmienne, mimo wszystko lepszym wydaje się je jawnie pobrać za pomocą odpowiednich funkcji. Ale to już w rozdziale o DOM
Podsumowanie
Ok podsumujmy powyższe rozważania.
Zmienne to rodzaje pudełek, w których możemy trzymać różne rzeczy.
Zmienne możemy tworzyć za pomocą słów kluczowych var/let/const, przy czym zalecane są te dwa ostatnie
Let/const różnią się od varów głównie zasięgiem oraz tym, że w jednym zasięgu (bloku) nie możemy ponownie tworzyć zmiennych o tej samej nazwie.
Hoisting to zjawisko wynoszenia na początek skryptu zmiennych i deklaracji funkcji
W naszych skryptach starajmy się używać jak najwięcej const - dzięki temu będziesz wyglądał jak pro. Jedynym wyjątkiem są liczniki oraz zmienne które wiemy, że zaraz zmienimy (np. toggleCatNightPartyMode)
I w zasadzie tyle. Cała reszta przyjdzie z praktyką. Nawet jeżeli na chwilę obecną powyższe rozważania wydają się dla ciebie dziwne, nie przejmuj się. Po 2-3 skryptach całość stanie się odruchem.
Last updated