• Aplikacje webowe
  • var w JavaScripcie - zakres, hoisting i pułapki starego kodu

var w JavaScripcie - zakres, hoisting i pułapki starego kodu

Przemysław Kwiatkowski 11 sierpnia 2026
HOISTING w JavaScript. Poznaj mechanizm podnoszenia zmiennych i funkcji.

Spis treści

W starym kodzie JavaScriptu słowo kluczowe var pojawia się bardzo często, ale jego działanie potrafi zaskoczyć nawet osoby znające let i const. Wyjaśniam, czym różni się deklaracja za pomocą var, jak działa hoisting i zakres funkcji oraz kiedy użycie tego rozwiązania w aplikacji webowej może prowadzić do trudnych do wykrycia błędów.

Najważniejsze zasady używania var w JavaScripcie

  • Zakres funkcji oznacza, że var nie respektuje zwykłego zakresu blokowego.
  • Hoisting przenosi deklarację zmiennej na początek zakresu, ale nie jej przypisaną wartość.
  • let i const są dziś zazwyczaj lepszym wyborem w nowym kodzie.
  • Powtórna deklaracja zmiennej za pomocą var jest dozwolona w tym samym zakresie.
  • Stary kod, skrypty i kompatybilność to główne sytuacje, w których nadal można spotkać uzasadnione użycie var.

Co oznacza var i dlaczego nadal się z nim spotykamy

var służy do deklarowania zmiennych, czyli nazw, pod którymi JavaScript przechowuje wartości. Można zadeklarować zmienną bez wartości albo od razu przypisać jej dane.

var username;
var points = 120;

username = "Ania";
points = points + 30;

Pierwsza zmienna ma początkowo wartość undefined. Druga otrzymuje liczbę już w chwili deklaracji. W praktyce nie trzeba określać typu danych, ponieważ JavaScript robi to dynamicznie podczas działania programu.

To najstarszy sposób deklarowania zmiennych w tym języku. Przed wprowadzeniem let i const w standardzie ECMAScript 2015 programiści korzystali właśnie z var. Dlatego starsze biblioteki, skrypty osadzone w stronach i część kodu produkcyjnego nadal go używają.

Sam fakt, że kod zawiera var, nie oznacza jeszcze błędu. Problem zaczyna się wtedy, gdy programista zakłada, że zmienna zachowuje się jak deklarowana wewnątrz bloku. Największa różnica dotyczy zakresu widoczności, a nie samego przechowywania wartości.

Zakres funkcji zmienia sposób działania zmiennej

Zmienna zadeklarowana za pomocą var ma zakres funkcji. Jeśli znajduje się wewnątrz funkcji, jest dostępna w całej tej funkcji, nawet gdy zapisano ją wewnątrz instrukcji if, pętli albo innego bloku.

function showMessage() {
  if (true) {
    var message = "Operacja zakończona";
  }

  console.log(message);
}

showMessage();

Ten kod zadziała, ponieważ blok if nie tworzy dla var osobnego zakresu. Zmienna jest widoczna w całej funkcji showMessage. Dla porównania let i const są ograniczone do bloku, w którym zostały zadeklarowane.

if (true) {
  let localMessage = "Tylko w tym bloku";
  const status = "OK";
}

console.log(localMessage); // ReferenceError
console.log(status);       // ReferenceError

W aplikacji webowej różnica może ujawnić się przy obsłudze formularzy, filtrów lub warunkowych fragmentów interfejsu. Zmienna, która miała istnieć tylko przez kilka instrukcji, zaczyna być dostępna dalej i może przypadkowo zostać nadpisana. Z mojego doświadczenia wynika, że wyciekanie zmiennych poza blok jest jednym z najczęstszych powodów, dla których stary kod JavaScriptu staje się trudny w utrzymaniu.

Jeżeli var zostanie użyte poza funkcją w klasycznym skrypcie, trafia do zakresu globalnego. W przeglądarce może wtedy stać się właściwością obiektu window. W module JavaScriptu zasady są inne, ponieważ najwyższy poziom modułu ma własny zakres i nie tworzy automatycznie globalnej właściwości.

Hoisting wyjaśnia pozornie dziwne wyniki

Hoisting, nazywany też wynoszeniem deklaracji, oznacza, że deklaracje var są przetwarzane przed wykonaniem kodu w danym zakresie. Nie oznacza to jednak, że JavaScript przenosi na początek również wartość przypisaną do zmiennej.

console.log(total); // undefined

var total = 50;

Silnik JavaScriptu interpretuje ten fragment w przybliżeniu tak:

var total;

console.log(total); // undefined

total = 50;

Dlatego odwołanie do zmiennej przed linią deklaracji nie kończy się tutaj błędem ReferenceError. Zmienna istnieje, ale nie ma jeszcze przypisanej wartości. Hoisting dotyczy deklaracji, nie inicjalizacji.

Właśnie ten mechanizm często utrudnia czytanie kodu. Program może działać, mimo że kolejność instrukcji sugeruje błąd. Nie traktowałbym tego jako wygodnej cechy, na której warto budować logikę aplikacji. Czytelniejsza praktyka polega na deklarowaniu zmiennej przed pierwszym użyciem.

W przypadku let i const również mówi się o hoistingu, ale przed wykonaniem deklaracji obowiązuje tak zwana temporal dead zone. Próba odwołania się do zmiennej przed jej deklaracją kończy się błędem. Taka restrykcja szybciej ujawnia pomyłki w kodzie.

Porównanie var, let i const w praktyce

W nowym kodzie aplikacji webowych wybór słowa kluczowego powinien wynikać z tego, czy zmienna będzie ponownie przypisywana i jak długo ma być widoczna. Poniższe zestawienie pokazuje najważniejsze różnice.

Cecha var let const
Zakres Funkcja lub globalny skrypt Blok Blok
Zmiana wartości Dozwolona Dozwolona Niedozwolona po przypisaniu
Brak wartości początkowej Dozwolony Dozwolony Niedozwolony
Powtórna deklaracja w tym samym zakresie Dozwolona Błąd składni Błąd składni
Odwołanie przed deklaracją Zwraca undefined Błąd wykonania Błąd wykonania

Najczęściej zaczynam od const. Jeśli wiem, że zmienna będzie otrzymywać nowe wartości, wybieram let. Po var sięgam przede wszystkim wtedy, gdy pracuję z istniejącym kodem, konkretnym ograniczeniem środowiska albo biblioteką, która wymaga starszego stylu.

Trzeba przy tym pamiętać, że const nie zamraża obiektu ani tablicy. Blokuje ponowne przypisanie zmiennej, ale zawartość obiektu nadal może się zmienić.

const user = {
  name: "Marek"
};

user.name = "Piotr"; // Działa

// user = {}; // TypeError

To rozróżnienie jest ważne w aplikacjach korzystających z danych formularza, konfiguracji i obiektów stanu. Stała referencja nie zawsze oznacza niezmienne dane.

Typowe błędy związane z var

Zmiana wartości poza zamierzonym blokiem

var isVisible = false;

if (userIsLoggedIn) {
  var isVisible = true;
}

console.log(isVisible);

Powtórna deklaracja nie tworzy nowej zmiennej ograniczonej do if. Modyfikuje tę samą zmienną. Przy większej funkcji taki kod może powodować trudne do odtworzenia błędy interfejsu, na przykład nieprawidłowe pokazywanie panelu użytkownika.

Powtórna deklaracja przez przypadek

var apiUrl = "/api/products";
var apiUrl = "/api/orders";

console.log(apiUrl); // "/api/orders"

JavaScript dopuszcza taki zapis, ale druga deklaracja może ukrywać zwykłą pomyłkę. Przy let i const podobny błąd jest zatrzymywany już na etapie parsowania kodu. To jedna z małych rzeczy, które w codziennej pracy robią dużą różnicę.

Problem z pętlami i funkcjami zwrotnymi

for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100);
}

Wynik to zwykle trzy razy 3, ponieważ wszystkie funkcje zwrotne korzystają z tej samej zmiennej i. Pętla kończy działanie, zanim opóźnione funkcje zostaną wykonane.

for (let i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100);
}

Wersja z let tworzy osobny zakres dla każdej iteracji, więc wypisuje 0, 1 i 2. Ten przykład dobrze pokazuje, że różnica między deklaracjami nie jest wyłącznie kwestią stylu. Może zmienić wynik działania kodu asynchronicznego.

Kiedy var ma jeszcze sens

W nowym projekcie najczęściej nie ma powodu, aby wybierać var zamiast let lub const. Nowoczesny standard JavaScriptu, moduły i narzędzia budujące aplikacje dobrze wspierają nowsze deklaracje.

Istnieją jednak sytuacje, w których jego obecność jest uzasadniona:

  • utrzymanie starszego kodu, którego nie chcemy od razu przepisywać,
  • zgodność ze starym środowiskiem lub ograniczonym narzędziem JavaScript,
  • analiza dawnych bibliotek, w których zakres funkcji był świadomym elementem projektu,
  • kod generowany przez starszy kompilator albo narzędzie transpilujące.

Nie przepisywałbym mechanicznie każdego var na let. Najpierw sprawdzam, czy zmienna nie jest wykorzystywana poza blokiem, czy nie zależy od powtórnej deklaracji oraz czy kod nie opiera się na specyficznym zachowaniu pętli. Automatyczna zamiana bez testów może zmienić działanie programu.

W nowej funkcji przyjmuję prostą regułę. Używam const, gdy nie przypisuję zmiennej nowej wartości. Wybieram let, gdy wartość ma się zmieniać. var zostawiam dla kodu, który rzeczywiście wymaga jego semantyki albo jest częścią starszego rozwiązania.

Jak bezpiecznie pracować z var w istniejącej aplikacji

Jeśli utrzymujesz starszą aplikację, zacznij od znalezienia zakresu każdej zmiennej. Sprawdź, czy deklaracja znajduje się w funkcji, czy na poziomie globalnym, oraz czy ta sama nazwa nie jest używana w kilku warunkach i pętlach.

  1. Znajdź wszystkie deklaracje var w danej funkcji.
  2. Sprawdź miejsca odwołań przed deklaracją.
  3. Poszukaj powtórnych deklaracji tej samej nazwy.
  4. Przeanalizuj pętle z funkcjami zwrotnymi i kodem asynchronicznym.
  5. Dopiero potem rozważ zamianę na let albo const.

Podczas refaktoryzacji szczególnie dokładnie testuję formularze, obsługę zdarzeń i fragmenty uruchamiane po czasie. To tam zakres zmiennej najczęściej wpływa na zachowanie użytkownika, choć sam kod wygląda na pozornie prosty.

Pomocne są też reguły lintingu, które ostrzegają przed użyciem var, niezdefiniowanymi zmiennymi i deklaracjami przesłaniającymi inne nazwy. Nie zastępują one rozumienia kodu, ale dobrze wyłapują powtarzalne problemy jeszcze przed uruchomieniem aplikacji.

Najlepsza decyzja zależy od wieku i roli kodu

var nie jest bezużyteczne, ale wymaga świadomości jego historycznych zasad. Zakres funkcji, hoisting i możliwość ponownej deklaracji sprawiają, że łatwiej nim przypadkowo stworzyć błąd niż za pomocą let lub const.

W nowej aplikacji webowej wybrałbym const jako domyślną opcję, let dla wartości, które faktycznie się zmieniają, a var traktowałbym jako narzędzie do obsługi istniejącego kodu i konkretnych ograniczeń. Taki podział jest prosty, czytelny i dobrze chroni przed problemami z zakresem.

Najważniejsze nie jest samo zapamiętanie trzech słów kluczowych, lecz zrozumienie, kiedy zmienna ma być widoczna, czy może zmienić wartość i jak zachowa się w kodzie asynchronicznym. Gdy te trzy pytania są jasne, wybór między var, let i const przestaje być zgadywaniem.

FAQ - Najczęstsze pytania

Zmienna zadeklarowana za pomocą var ma zakres całej funkcji, więc pozostaje dostępna także poza blokiem if, pętlą lub innym blokiem. W przeciwieństwie do niej let i const są ograniczone do miejsca deklaracji. Może to prowadzić do przypadkowego nadpisania wartości w formularzach, filtrach i interfejsie.

Hoisting przenosi deklarację var na początek zakresu, ale nie przenosi przypisanej wartości. Dlatego przed wykonaniem przypisania zmienna istnieje, lecz ma wartość undefined. W przypadku let i const odwołanie przed deklaracją kończy się błędem wykonania z powodu temporal dead zone.

const warto stosować, gdy zmienna nie otrzymuje nowej wartości, a let, gdy będzie ponownie przypisywana. var ma uzasadnienie głównie przy utrzymaniu starszego kodu, wymaganiach ograniczonego środowiska, dawnych bibliotekach lub kodzie generowanym przez starsze narzędzia. Nie należy zamieniać go mechanicznie bez sprawdzenia zakresów, powtórnych deklaracji i testów.

W pętli z var wszystkie funkcje zwrotne korzystają z tej samej zmiennej i. Pętla kończy się, zanim funkcje uruchomione przez setTimeout zostaną wykonane, dlatego każda widzi końcową wartość 3. Użycie let tworzy osobny zakres dla każdej iteracji i daje wynik 0, 1 oraz 2.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

javascript
var
hoisting
zakres funkcji
refaktoryzacja
Autor Przemysław Kwiatkowski
Przemysław Kwiatkowski
Jestem Przemysław i od 15 lat zajmuję się programowaniem .NET, chmurą Azure oraz sztuczną inteligencją. Moja przygoda z tymi technologiami zaczęła się od fascynacji możliwościami, jakie dają, a z czasem przerodziła się w pasję do tworzenia rozwiązań, które realnie wpływają na pracę i życie ludzi. Na kursdotnet.pl staram się dzielić się swoją wiedzą w sposób przystępny, tłumacząc złożone zagadnienia i pomagając zrozumieć, jak te dynamicznie rozwijające się obszary IT mogą być wykorzystane w praktyce. Dokładam wszelkich starań, aby prezentowane przeze mnie materiały były rzetelne, aktualne i oparte na sprawdzonych źródłach, a także aby uporządkować wiedzę w sposób ułatwiający jej przyswojenie.

Udostępnij artykuł

Napisz komentarz