Zmienne

Zmienne to struktura danych, która przypisuje wartości reprezentatywną nazwę. Mogą one zawierać dowolne dane.

Nazwa zmiennej jest nazywana identyfikatorem. Prawidłowy identyfikator musi być zgodny z tymi zasadami:

  • Identyfikatory mogą zawierać litery Unicode, znaki dolara ($), podkreślenia (_), cyfry (0–9), a nawet niektóre znaki Unicode.
  • Identyfikatory nie mogą zawierać odstępów, bo parser używa odstępów do rozdzielania elementów wejściowych. Jeśli na przykład spróbujesz wywołać zmienną my Variable zamiast myVariable, parser wykryje 2 identyfikatory: my i Variable, a potem zgłosi błąd składni („nieoczekiwany token: identyfikator”).
  • Identyfikatory muszą zaczynać się od litery, podkreślenia (_) lub znaku dolara ($). Nie mogą zaczynać się od cyfr, aby uniknąć pomylenia między liczbami a identyfikatorami:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    Jeśli JavaScript dopuszczałby się na początku identyfikatora, dopuszczałoby to stosowanie identyfikatorów składających się tylko z liczb, powodując konflikty między liczbami a liczbami używanymi jako identyfikatory:

    let 10 = 20
    
    10 + 5
    > ?
    
  • Zarezerwowane słowa, które mają już znaczenie składniowe, nie mogą być używane jako identyfikatory.

  • Identyfikatory nie mogą zawierać znaków specjalnych (! . , / \ + - * =).

Podane niżej reguły nie są rygorystyczne, ale stanowią sprawdzone metody branżowe, które ułatwiają utrzymanie kodu. Jeśli Twój projekt ma inne standardy, zastosuj się do nich, aby zachować spójność.

Na podstawie przykładu wskazanego przez wbudowane metody i właściwości JavaScriptu stosowaną konwencją identyfikatorów składających się z wielu słów jest wielkość wielbłąda (określana również jako „camelCase”). Wielkość liter to metoda, która polega na umieszczaniu pierwszych liter na początku każdego wyrazu z wyjątkiem pierwszej, aby poprawić czytelność tekstu bez spacji.

let camelCasedIdentifier = true;

W niektórych projektach stosowane są inne konwencje nazewnictwa w zależności od kontekstu i charakteru danych. Na przykład pierwsza litera nazwy klasy jest zwykle pisana wielką literą, dlatego w nazwach klas wielowyrazowych często stosuje się pisownię wielkimi literami wielbłąda, nazywaną też „wielkią literą wielbłąda” lub „Pascalem”.

class MyClass {

}

Identyfikatory powinny zwięźle opisać charakter zawartych w nich danych (np. currentMonthDays to lepsza nazwa niż theNumberOfDaysInTheCurrentMonth) i szybko je odczytać (originalValue jest lepszy niż val). Identyfikatory myVariable używane w tym module działają w kontekście wyodrębnionych przykładów, ale byłyby bardzo nieprzydatne w kodzie produkcyjnym, ponieważ nie zawierają informacji o zawartościach identyfikatorów.

Identyfikatory nie powinny być zbyt szczegółowe w odniesieniu do zawartych w nich danych, ponieważ ich wartości mogą się zmieniać w zależności od tego, jak skrypty korzystają z tych danych, lub od decyzji podejmowanych przez przyszłych opiekunów. Na przykład zmienną, oryginalnie podającą identyfikator miles, może trzeba będzie zmienić w kilometrach później w projekcie, co będzie wymagało zmiany odwołań do tej zmiennej, aby uniknąć nieporozumień w przyszłości. Aby temu zapobiec, użyj distance jako identyfikatora.

JavaScript nie nadaje żadnych specjalnych uprawnień ani znaczenia identyfikatorom rozpoczynającym się od znaku podkreślenia (_), ale zwykle używa się ich do pokazania, że zmienna, metoda lub właściwość są „prywatne”, co oznacza, że jest przeznaczona do użytku wyłącznie w kontekście obiektu, który je zawiera, i nie należy do niej uzyskiwać dostępu ani modyfikować poza tym kontekstem. Jest to konwencja przeniesiona z innych języków programowania, która poprzedzała dodanie prywatnych właściwości JavaScriptu.

Deklaracja zmiennej

Jest wiele sposobów na rozpoznanie identyfikatora przez JavaScript. Jest to proces nazywany „deklarowaniem” zmiennej. Zmienna jest deklarowana za pomocą słów kluczowych let, const lub var.

let myVariable;

Użyj funkcji let lub var, aby zadeklarować zmienną, którą można w każdej chwili zmienić. Te słowa kluczowe informują tłumacze JavaScriptu, że ciąg znaków jest identyfikatorem, który może zawierać wartość.

Pracując w nowoczesnej bazie kodu, używaj let zamiast var. var nadal działa w nowoczesnych przeglądarkach, ale ma pewne nieintuicyjne działania zdefiniowane w najstarszych wersjach JavaScriptu, którego nie można później zmienić, by zachować zgodność wsteczną. W ES6 dodaliśmy let, aby rozwiązać problemy z projektem var.

Zadeklarowana zmienna jest inicjowana przez przypisanie do niej wartości. Aby przypisać lub zmienić wartość zmiennej, użyj pojedynczego znaku równości (=). Możesz to zrobić w ramach tego samego oświadczenia:

let myVariable = 5;

myVariable + myVariable
> 10

Możesz też zadeklarować zmienną z parametrem let (lub var) bez jej inicjowania. Jeśli to zrobisz, początkowa wartość zmiennej będzie wynosić undefined, dopóki nie zostanie jej przypisana przez kod.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

Zmienna z wartością undefined różni się od niezdefiniowanej zmiennej, której identyfikator nie został jeszcze zadeklarowany. Odwołanie do niezadeklarowanej zmiennej powoduje błąd.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

Powiązanie identyfikatora z wartością jest zwykle nazywane „powiązaniem”. Składnia, która występuje po słowach kluczowych let, var lub const, jest nazywana „listą powiązań” i pozwala na utworzenie wielu deklaracji zmiennych rozdzielonych przecinkami (kończących się oczekiwanym średnikiem). Dzięki temu poniższe fragmenty kodu działają tak samo:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

Ponowne przypisanie wartości zmiennej nie spowoduje użycia właściwości let (ani var), ponieważ JavaScript wie już, że zmienna istnieje:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

Możesz przypisywać zmiennym nowe wartości na podstawie ich istniejących wartości:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

Jeśli spróbujesz ponownie zadeklarować zmienną za pomocą funkcji let w środowisku produkcyjnym, pojawi się błąd składni:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

Narzędzia dla programistów w przeglądarkach mniej rygorystycznie podchodzą do ponownej deklaracji let (i class), więc ten sam błąd może się nie pojawić w konsoli programisty.

Aby zachować zgodność ze starszą wersją przeglądarek, var umożliwia niepotrzebne ponowne deklaracja bez błędów w żadnym kontekście:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

Za pomocą słowa kluczowego const możesz zadeklarować stałą, czyli typ zmiennej, którą trzeba natychmiast zainicjować, a potem nie można jej zmienić. Identyfikatory stałych są zgodne z tymi samymi regułami co zmienne zadeklarowane za pomocą funkcji let (i var):

const myConstant = true;

myConstant
> true

Nie możesz zadeklarować stałej bez natychmiastowego przypisania jej wartości, ponieważ stałych wartości nie można zmieniać po ich utworzeniu, więc każda niezainicjowana stała będzie obowiązywać przez zawsze undefined. Jeśli spróbujesz zadeklarować stałą bez jej zainicjowania, pojawi się błąd składni:

const myConstant;
Uncaught SyntaxError: missing = in const declaration

Próba zmiany wartości zmiennej zadeklarowanej za pomocą funkcji const w taki sposób, w jaki można zmienić wartość zmiennej zadeklarowanej za pomocą funkcji let (lub var), powoduje błąd typu:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

Jeśli jednak z obiektem powiązana jest stała, można zmieniać właściwości tego obiektu.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

Stała, która zawiera obiekt, jest trwałym odwołaniem do zmiennej wartości danych. Chociaż nie można zmienić samej stałej, można zmodyfikować, dodać lub usunąć właściwości obiektu, do którego odwołuje się obiekt:

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

Jeśli nie spodziewasz się ponownego przypisania zmiennej, najlepiej ustawić ją jako stałą. Użycie właściwości const informuje zespół programistów lub przyszłych opiekunów projektu, aby nie zmieniali tej wartości. Pozwoli to uniknąć naruszenia założeń dotyczących sposobu wykorzystania kodu (na przykład że zmienna zostanie ostatecznie oceniana pod kątem oczekiwanego typu danych).

Zakres zmiennej

Zakres zmiennej to część skryptu, w której ta zmienna jest dostępna. Poza zakresem zmiennej nie zostanie ona zdefiniowana – nie jako identyfikator zawierająca wartość undefined, ale jak gdyby nie została zadeklarowana.

W zależności od słowa kluczowego, którego używasz do zadeklarowania zmiennej, i kontekstu, w którym ją zdefiniujesz, możesz określić zakres zmiennych, by blokować instrukcje (zakres blokowania), poszczególne funkcje (zakres funkcji) lub całą aplikację JavaScript (zakres globalny).

Zablokuj zakres

Każda zmienna zadeklarowana za pomocą let lub const jest ograniczona do najbliższej zawierającej instrukcję blokowania, co oznacza, że dostęp do zmiennej można uzyskać tylko w obrębie tego bloku. Próba uzyskania dostępu do zmiennej o zakresie na poziomie bloku poza jej blokiem, który zawiera, powoduje ten sam błąd co w przypadku próby uzyskania dostępu do zmiennej, która nie istnieje:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

W przypadku JavaScriptu poza bloku, który go zawiera, nie występuje zmienna o zakresie na poziomie bloku. Na przykład możesz zadeklarować stałą w bloku, a następnie inną stałą poza tym blokiem, która korzysta z tego samego identyfikatora:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

Chociaż zadeklarowana zmienna nie może wykraczać poza swój blok nadrzędny, jest dostępna dla wszystkich bloków podrzędnych:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

Wartość zadeklarowanej zmiennej można zmienić z poziomu bloku podrzędnego:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

Nową zmienną można zainicjować bez błędów za pomocą let lub const wewnątrz bloku podrzędnego, nawet jeśli używa ona tego samego identyfikatora co zmienna w bloku nadrzędnym:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

Zakres funkcji

Zmienne zadeklarowane za pomocą funkcji var są ograniczone do najbliższej funkcji zawierającej (lub statycznego bloku inicjowania w klasie).

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

Dzieje się tak nadal po wywołaniu funkcji. Mimo że zmienna jest inicjowana w trakcie wykonywania funkcji, nadal jest niedostępna poza zakresem funkcji:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

Zakres globalny

Zmienna globalna jest dostępna w całej aplikacji JavaScript, niezależnie od bloków i funkcji, dla każdego skryptu na stronie.

Choć może się to wydawać pożądaną wartością domyślną, zmienne, do których dowolna część aplikacji może uzyskiwać dostęp i które mogą być modyfikowane, mogą zwiększyć nakład pracy, a nawet powodować kolizje ze zmiennymi w innym miejscu aplikacji o tym samym identyfikatorze. Dotyczy to całego kodu JavaScriptu związanego z renderowaniem strony, w tym bibliotek zewnętrznych i statystyk użytkowników. Dlatego w miarę możliwości należy unikać zanieczyszczenia zakresu globalnego.

Każda zmienna zadeklarowana za pomocą funkcji var poza funkcją nadrzędną lub za pomocą funkcji let bądź const poza blokiem nadrzędnym jest globalna:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

Przypisanie wartości do zmiennej bez jej jawnego zadeklarowania (czyli nigdy do jej utworzenia za pomocą elementów var, let ani const) podnosi zmienną do zakresu globalnego, nawet jeśli została zainicjowana w ramach funkcji lub bloku. Zmienna utworzona z użyciem tego wzorca jest czasami nazywana „domniemanym globalnym”.

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

Z możliwością podnoszenia

Zmienne i deklaracje funkcji są przenoszone na początek zakresu, co oznacza, że interpreter JavaScript przetwarza wszystkie zmienne zadeklarowane w dowolnym punkcie skryptu i skutecznie przenosi je do pierwszego wiersza zakresu obejmującego przed wykonaniem skryptu. Oznacza to, że do zmiennej zadeklarowanej za pomocą var można się odwołać przed jej zadeklarowaniem bez wystąpienia błędu:

hoistedVariable
> undefined

var hoistedVariable;

Ponieważ hostowana jest tylko deklaracja zmiennej, a nie inicjowanie, zmienne, które nie zostały jawnie zadeklarowane za pomocą var, let lub const, nie są przesyłane:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

Jak już wspomnieliśmy, do zadeklarowanej, ale niezainicjowanej zmiennej, przypisywana jest wartość undefined. Odnosi się to też do deklaracji zmiennych przeniesionych, ale tylko do tych zadeklarowanych za pomocą funkcji var.

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

To nieintuicyjne działanie jest w dużej mierze podstawą decyzji projektowych podejmowanych w najstarszych wersjach JavaScriptu i nie można zmienić bez ryzyka uszkodzenia istniejących witryn.

Metody let i const rozwiązują ten problem, ponieważ generują błąd w przypadku uzyskania dostępu do zmiennej przed jej utworzeniem:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

Różni się on od błędu „hoistedużywanie niezdefiniowanej zmiennej”, który możesz spodziewać się przy próbie uzyskania dostępu do niezadeklarowanej zmiennej. JavaScript pobrał zmienną, więc wie, że zostanie ona utworzona w określonym zakresie. Jednak zamiast udostępniać tę zmienną przed jej deklaracjami z wartością undefined, interpreter zgłasza błąd. Zmienne zadeklarowane z funkcją let lub const (albo class) stwierdzają, że istnieją w „tymczasowej martwej strefie” („TDZ”) od początku ich bloku do punktu w kodzie, w którym zmienna jest zadeklarowana.

Tymczasowa strefa martwych danych sprawia, że zachowanie autora let jest bardziej intuicyjne niż działanie var. Ważny jest także projekt urządzenia const. Nie można zmieniać stałych, dlatego nie można zainicjować stałej wartości podniesionej na początek zakresu i przypisanej do niej niejawnej wartości undefined z wartością znaczącą.

Sprawdź swoją wiedzę

Od jakich znaków możesz zacząć identyfikator?

List
Podkreślenie
Cyfra

Jaka jest preferowana metoda deklarowania zmiennej, której wartość można w dowolnym momencie zmienić?

pozwól
const
var