Warning: session_start(): open(/home/klient.dhosting.pl/key2print/.tmp//sess_f0fe691c818d535bc8bbbabf61f12a46, O_RDWR) failed: Disk quota exceeded (122) in /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/pixelyoursite-pro/includes/class-pys.php on line 392

Warning: session_start(): Failed to read session data: files (path: /home/klient.dhosting.pl/key2print/.tmp/) in /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/pixelyoursite-pro/includes/class-pys.php on line 392
JavaScript: let vs var - różnice i kiedy używać którego - Codelivery

CODELIVERY BLOG

JavaScript: let vs var – różnice i kiedy używać którego

utworzone przez | lis 5, 2025 | Bez kategorii

Best Asset management alternatives in 2024

Spis Treści

Let i var to dwa sposoby deklarowania zmiennych w JavaScript, które różnią się fundamentalnie pod względem zasięgu (scope), hoistingu i możliwości ponownej deklaracji. Wprowadzenie let w ES6 (2015) było odpowiedzią na problemy i nieintuicyjne zachowania var, które przez lata frustraowały programistów i prowadziły do trudnych do znalezienia bugów.

Dla developerów uczących się JavaScript lub migrujących legacy code do nowoczesnych standardów, zrozumienie różnic między let a var jest kluczowe dla pisania czystego, przewidywalnego kodu bez subtelnych błędów związanych z zakresem zmiennych.

Zasięg (Scope) – fundamentalna różnica

Var ma zasięg funkcyjny (function scope), co oznacza, że zmienna jest widoczna w całej funkcji, niezależnie od bloku w którym została zadeklarowana. Nawet jeśli zadeklarujesz var wewnątrz pętli for czy bloku if, będzie dostępna poza tym blokiem, ale tylko w ramach funkcji.

javascript

function testVar() {
    if (true) {
        var x = 10;
    }
    console.log(x); // 10 - działa!
}

Let ma zasięg blokowy (block scope), co jest bardziej intuicyjne i zgodne z większością innych języków programowania. Zmienna zadeklarowana z let istnieje tylko w bloku, w którym została utworzona – wewnątrz {}.

javascript

function testLet() {
    if (true) {
        let y = 10;
    }
    console.log(y); // ReferenceError: y is not defined
}

To zachowanie let eliminuje całą klasę bugów związanych z niezamierzonym wyciekaniem zmiennych poza ich logiczny kontekst.

Hoisting – wyciąganie deklaracji

Var jest hoistowany – deklaracja jest przenoszona na początek funkcji podczas kompilacji, ale inicjalizacja pozostaje w miejscu. To prowadzi do sytuacji, gdzie można odwoływać się do zmiennej przed jej deklaracją, otrzymując undefinedzamiast błędu.

javascript

console.log(a); // undefined (nie błąd!)
var a = 5;
console.log(a); // 5

Let też jest hoistowany, ale znajduje się w „temporal dead zone” od początku bloku do momentu deklaracji. Odwołanie przed deklaracją powoduje ReferenceError.

javascript

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 5;
console.log(b); // 5

Temporal dead zone wymusza deklarowanie zmiennych przed ich użyciem, co jest dobrą praktyką programistyczną i zapobiega subtelnym błędom.

Ponowna deklaracja

Var pozwala na ponowną deklarację tej samej zmiennej w tym samym zasięgu bez błędu. To może prowadzić do przypadkowego nadpisywania zmiennych.

javascript

var name = "Jan";
var name = "Anna"; // działa, nadpisuje bez ostrzeżenia
console.log(name); // "Anna"

Let nie pozwala na ponowną deklarację w tym samym zasięgu, rzucając błąd składni. To chroni przed przypadkowym nadpisaniem.

javascript

let name = "Jan";
let name = "Anna"; // SyntaxError: Identifier 'name' has already been declared

Możesz jednak ponownie przypisać wartość do zmiennej let (reassignment), co jest różne od re-declaration:

javascript

let name = "Jan";
name = "Anna"; // OK - reassignment

Pętle i zamknięcia (closures)

Var w pętlach tworzy jedną współdzieloną zmienną dla wszystkich iteracji, co prowadzi do słynnego problemu z setTimeout:

javascript

for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Wypisze: 3, 3, 3 (nie 0, 1, 2!)

Let w pętlach tworzy nową zmienną dla każdej iteracji, co rozwiązuje problem:

javascript

for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Wypisze: 0, 1, 2 (jak oczekiwano)

To zachowanie let eliminuje potrzebę IIFE (Immediately Invoked Function Expression) czy innych workarounds używanych z var.

Zmienne globalne i window object

Var w scope globalnym tworzy właściwość obiektu window w przeglądarce:

javascript

var globalVar = "test";
console.log(window.globalVar); // "test"

Let w scope globalnym nie dodaje właściwości do window:

javascript

let globalLet = "test";
console.log(window.globalLet); // undefined

To zapobiega przypadkowemu zanieczyszczaniu globalnej przestrzeni nazw i konfliktom z właściwościami window.

Gemini Generated Image tujo10tujo10tujo
JavaScript: let vs var - różnice i kiedy używać którego 2

Kiedy używać którego

Zawsze używaj let (lub const) w nowoczesnym JavaScript. ES6+ best practices zalecają:

  • const jako default dla wartości, które nie będą reassignowane
  • let dla zmiennych, które będą reassignowane
  • var praktycznie nigdy w nowym kodzie

Legacy code może wymagać używania var dla kompatybilności z bardzo starymi przeglądarkami (pre-2015), ale transpilery jak Babel pozwalają pisać nowoczesny kod z let/const kompilując do var dla starych środowisk.

Linting i Code Quality – ESLint z regułami no-var i prefer-const wymusza nowoczesne praktyki, automatycznie flagując użycie var jako code smell.

Migracja z var do let/const

Przy refaktoringu legacy code:

  1. Zamień wszystkie var na let
  2. Przetestuj dokładnie – zmiany w scope mogą ujawnić ukryte bugi
  3. Zmień let na const wszędzie gdzie możliwe
  4. Uruchom testy jednostkowe i integracyjne

Automatyczne narzędzia jak ESLint z --fix mogą pomóc, ale ręczna weryfikacja jest kluczowa dla critical code.

Wprowadzenie let i const w ES6 było jedną z najważniejszych poprawek JavaScript, eliminując źródło niezliczonych bugów i frustracji. Dla każdego współczesnego projektu JavaScript, var powinien być traktowany jako przestarzały, a letconst jako standard. Block scope, temporal dead zone i zakaz re-declaration czynią kod bardziej przewidywalnym i łatwiejszym w utrzymaniu.


Bibliografia:

  1. „You Don’t Know JS: Scope & Closures” – Kyle Simpson (2014)
  2. „JavaScript: The Definitive Guide, 7th Edition” – David Flanagan (2020)
  3. MDN Web Docs – „let” – https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
  4. MDN Web Docs – „var” – https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
  5. „Exploring ES6” – Dr. Axel Rauschmayer (2015)
  6. ECMAScript 2015 Language Specification – https://www.ecma-international.org/ecma-262/6.0/
  7. ESLint Documentation – „no-var” rule – https://eslint.org/docs/rules/no-var

Let’s deliver great things together.

Reach out to discuss your next big idea.

Get in Touch: Leave Your Message Here!

In 2012, I invested in a project led by Marek and Dominik. Throughout the investment period, the company demonstrated creativity, and their pivots were successfully implemented by the team.

Rafał Brzoska

CEO at InPost

Agreement


Fatal error: Uncaught ErrorException: md5_file(/home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/litespeed/css/56422efa90061beaadca96f07cea844d.css.tmp): Failed to open stream: No such file or directory in /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php:149 Stack trace: #0 [internal function]: litespeed_exception_handler(2, 'md5_file(/home/...', '/home/klient.dh...', 149) #1 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php(149): md5_file('/home/klient.dh...') #2 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(837): LiteSpeed\Optimizer->serve('https://codeliv...', 'css', true, Array) #3 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(333): LiteSpeed\Optimize->_build_hash_url(Array) #4 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(264): LiteSpeed\Optimize->_optimize() #5 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimize.cls.php(225): LiteSpeed\Optimize->_finalize('<br />\n<b>Warni...') #6 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/class-wp-hook.php(341): LiteSpeed\Optimize->finalize('<br />\n<b>Warni...') #7 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/plugin.php(205): WP_Hook->apply_filters('<br />\n<b>Warni...', Array) #8 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/core.cls.php(459): apply_filters('litespeed_buffe...', '<br />\n<b>Warni...') #9 [internal function]: LiteSpeed\Core->send_headers_force('<br />\n<b>Warni...', 9) #10 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/functions.php(5481): ob_end_flush() #11 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/class-wp-hook.php(341): wp_ob_end_flush_all('') #12 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/class-wp-hook.php(365): WP_Hook->apply_filters(NULL, Array) #13 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/plugin.php(522): WP_Hook->do_action(Array) #14 /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-includes/load.php(1308): do_action('shutdown') #15 [internal function]: shutdown_action_hook() #16 {main} thrown in /home/klient.dhosting.pl/key2print/codelivery.eu-ahz9/public_html/wp-content/plugins/litespeed-cache/src/optimizer.cls.php on line 149