Variablen sind Container für Daten in deinem Programm. In JavaScript gibt es drei Wege, Variablen zu deklarieren: var, let und const. Jede hat unterschiedliche Eigenschaften und Einsatzbereiche. In diesem Tutorial lernst du, welche du wann nutzen solltest und was Scopes sind.
Variablen deklarieren: var, let, const
let – Die moderne Variablendeklaration
let ist seit ES6 (2015) der Standard für veränderbare Variablen:
let name = 'Max';
console.log(name); // Max
name = 'Maxine'; // Wert ändern ist erlaubt
console.log(name); // Maxine
let age; // Deklaration ohne Initialisierung
console.log(age); // undefined
age = 30; // Später zuweisen
Wann nutzen? Wenn der Wert sich ändern soll (Counter, User-Input, Loop-Variablen).
const – Konstanten für unveränderliche Werte
const erstellt Konstanten, die nach der Initialisierung nicht neu zugewiesen werden können:
const PI = 3.14159;
console.log(PI); // 3.14159
PI = 3.14; // ❌ TypeError: Assignment to constant variable
// const muss sofort initialisiert werden
const birthYear; // ❌ SyntaxError: Missing initializer
Wichtig: Bei Objekten/Arrays schützt const nur die Referenz, nicht den Inhalt:
const user = { name: 'Max', age: 25 };
user.age = 26; // ✅ Erlaubt – Objekt-Eigenschaften ändern
console.log(user); // { name: 'Max', age: 26 }
user = { name: 'Anna' }; // ❌ TypeError – Neu-Zuweisung verboten
const numbers = [1, 2, 3];
numbers.push(4); // ✅ Erlaubt – Array mutieren
console.log(numbers); // [1, 2, 3, 4]
numbers = [5, 6]; // ❌ TypeError – Neu-Zuweisung verboten
Wann nutzen? Standard für alle Variablen, außer du weißt, dass du neu zuweisen musst. Modern JavaScript bevorzugt const.
var – Die alte Variablendeklaration (vermeiden!)
var war bis ES6 die einzige Option, hat aber problematische Eigenschaften:
var oldStyle = 'Legacy Code';
console.log(oldStyle); // Legacy Code
oldStyle = 'Neuer Wert'; // Neu-Zuweisung erlaubt (wie let)
Warum var vermeiden?
- Function Scope statt Block Scope (siehe unten)
- Hoisting mit undefined (verwirrend)
- Re-Deklaration erlaubt (fehleranfällig)
var x = 5;
var x = 10; // ✅ Erlaubt, aber verwirrend!
console.log(x); // 10
let y = 5;
let y = 10; // ❌ SyntaxError: Identifier 'y' has already been declared
Faustregel: Nutze var nur in Legacy-Code, den du nicht ändern darfst.
Variable Scopes: Wo ist eine Variable sichtbar?
Scope bestimmt, wo im Code eine Variable verfügbar ist. JavaScript hat drei Scope-Arten:
1. Block Scope (let, const)
Ein Block ist Code zwischen { }. let und const sind nur innerhalb ihres Blocks sichtbar:
{
let blockVar = 'Nur hier sichtbar';
console.log(blockVar); // ✅ Nur hier sichtbar
}
console.log(blockVar); // ❌ ReferenceError: blockVar is not defined
Praktisches Beispiel – if-Block:
let score = 85;
if (score >= 50) {
let message = 'Bestanden!';
console.log(message); // ✅ Bestanden!
}
console.log(message); // ❌ ReferenceError – message existiert nur im if-Block
Loops isolieren Variablen:
for (let i = 0; i < 3; i++) {
console.log(i); // 0, 1, 2
}
console.log(i); // ❌ ReferenceError – i existiert nur im Loop
Mit var passiert das NICHT:
for (var j = 0; j < 3; j++) {
console.log(j); // 0, 1, 2
}
console.log(j); // ✅ 3 – var "leakt" aus dem Block!
2. Function Scope (var, let, const)
Variablen innerhalb einer Funktion sind immer nur dort sichtbar (egal ob var, let, const):
function myFunction() {
var funcVar = 'Nur in der Funktion';
let funcLet = 'Auch nur hier';
const funcConst = 'Ebenfalls lokal';
console.log(funcVar, funcLet, funcConst); // ✅ Alle verfügbar
}
myFunction();
console.log(funcVar); // ❌ ReferenceError – alle nicht verfügbar außerhalb
Nested Functions (verschachtelt):
function outer() {
let outerVar = 'Außen';
function inner() {
let innerVar = 'Innen';
console.log(outerVar); // ✅ Zugriff auf outer-Variable
console.log(innerVar); // ✅ Eigene Variable
}
inner();
console.log(innerVar); // ❌ ReferenceError – innerVar ist im inner-Scope
}
outer();
Regel: Innere Funktionen können auf äußere Variablen zugreifen, aber nicht umgekehrt.
3. Global Scope
Variablen außerhalb von Funktionen/Blöcken sind global:
let globalVar = 'Überall verfügbar';
function test() {
console.log(globalVar); // ✅ Zugriff möglich
}
test();
console.log(globalVar); // ✅ Auch hier
Im Browser: Globale var-Variablen werden zu window-Eigenschaften:
var globalWithVar = 'test';
console.log(window.globalWithVar); // ✅ 'test'
let globalWithLet = 'test';
console.log(window.globalWithLet); // ❌ undefined – let/const nicht am window
Best Practice: Vermeide globale Variablen (Namespace-Kollisionen, schwer zu debuggen).
Hoisting: Variablen “nach oben ziehen”
JavaScript verschiebt Deklarationen an den Anfang ihres Scopes (Hoisting), aber nicht die Initialisierung.
Hoisting mit var (problematisch)
console.log(x); // undefined (nicht ReferenceError!)
var x = 5;
console.log(x); // 5
Was passiert intern:
var x; // Deklaration wird "hochgezogen"
console.log(x); // undefined – Variable existiert, hat aber keinen Wert
x = 5; // Initialisierung bleibt hier
console.log(x); // 5
Hoisting mit let/const (Temporal Dead Zone)
let und const werden auch gehoisted, aber landen in der Temporal Dead Zone (TDZ) – Zugriff vor Deklaration ist verboten:
console.log(y); // ❌ ReferenceError: Cannot access 'y' before initialization
let y = 10;
Temporal Dead Zone visualisiert:
// TDZ starts here for 'myVar'
console.log(myVar); // ❌ ReferenceError
let myVar = 5; // TDZ ends – ab hier verfügbar
console.log(myVar); // ✅ 5
Warum ist das gut? Erzwingt sauberen Code – Variablen müssen deklariert werden, bevor du sie nutzt.
Funktions-Hoisting
Funktionsdeklarationen werden komplett gehoisted:
greet(); // ✅ Funktioniert! Output: Hallo!
function greet() {
console.log('Hallo!');
}
Aber: Function Expressions (mit const/let) werden nicht gehoisted:
sayHi(); // ❌ ReferenceError: Cannot access 'sayHi' before initialization
const sayHi = function() {
console.log('Hi!');
};
Variable Naming Rules
JavaScript hat klare Regeln für Variablennamen:
Erlaubt:
let userName = 'Max'; // ✅ camelCase (Best Practice)
let _private = 'secret'; // ✅ Underscore erlaubt
let $jquery = 'library'; // ✅ Dollar-Zeichen erlaubt
let user2 = 'Second User'; // ✅ Zahlen erlaubt (nicht am Anfang!)
let währung = 'Euro'; // ✅ Unicode (aber nicht empfohlen)
Verboten:
let 2user = 'Invalid'; // ❌ Zahl am Anfang
let user-name = 'Invalid'; // ❌ Bindestrich nicht erlaubt
let class = 'Reserved'; // ❌ Reserved Keyword
let let = 'Invalid'; // ❌ Reserved Keyword
Reserved Keywords (nicht verwenden):
break, case, catch, class, const, continue, debugger, default, delete,
do, else, export, extends, finally, for, function, if, import, in,
instanceof, let, new, return, super, switch, this, throw, try, typeof,
var, void, while, with, yield
Naming Conventions (Best Practices):
// camelCase für Variablen und Funktionen
let userName = 'Max';
function getUserData() { }
// PascalCase für Klassen
class UserAccount { }
// UPPER_CASE für Konstanten (echte Konstanten, nicht nur const)
const API_KEY = 'abc123';
const MAX_RETRIES = 3;
// Beschreibende Namen
let age = 25; // ✅ Gut
let a = 25; // ❌ Nicht aussagekräftig
// Boolean mit is/has/can Präfix
let isActive = true;
let hasPermission = false;
let canEdit = true;
Scope Chain: Wie JavaScript Variablen findet
JavaScript sucht Variablen von innen nach außen:
let global = 'global';
function outer() {
let outerVar = 'outer';
function inner() {
let innerVar = 'inner';
console.log(innerVar); // 1. Sucht in innerem Scope ✅
console.log(outerVar); // 2. Sucht in outer Scope ✅
console.log(global); // 3. Sucht in global Scope ✅
console.log(notExist); // 4. Nicht gefunden ❌ ReferenceError
}
inner();
}
outer();
Shadowing (Überschatten):
let name = 'Global Max';
function test() {
let name = 'Local Anna'; // Überschattet die globale Variable
console.log(name); // Local Anna
}
test();
console.log(name); // Global Max – unverändert
Praktische Beispiele
Counter mit let vs. var in Loops
Problem mit var:
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Output: 3, 3, 3 (!)
}, 100);
}
Warum? var hat Function Scope – alle Timeouts teilen sich dasselbe i, das am Ende 3 ist.
Lösung mit let:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Output: 0, 1, 2 ✅
}, 100);
}
Warum? let hat Block Scope – jede Iteration bekommt ihr eigenes i.
Konfiguration mit const
const CONFIG = {
apiUrl: 'https://api.example.com',
timeout: 5000,
debug: true
};
// Eigenschaften ändern ist OK
CONFIG.debug = false; // ✅
// Neu-Zuweisung verboten
CONFIG = { }; // ❌ TypeError
Best Practices Zusammenfassung
- Standard: const – Verwende
constfür alles, was nicht neu zugewiesen wird - Bei Bedarf: let – Nutze
letfür Counter, Flags, Re-Assignments - Niemals: var – Vermeide
varin neuem Code - Block Scope nutzen – Variablen so lokal wie möglich definieren
- Beschreibende Namen –
userAgestatta - UPPER_CASE für Konstanten –
const MAX_SIZE = 100
// ✅ Modern und sauber
const API_ENDPOINT = 'https://api.example.com';
let requestCount = 0;
function fetchData() {
const url = `${API_ENDPOINT}/users`;
requestCount++; // let erlaubt Änderung
// url bleibt lokal im Function Scope
console.log(url);
}
Nächste Schritte
Du verstehst jetzt:
- Den Unterschied zwischen
var,letundconst - Block, Function und Global Scope
- Hoisting und Temporal Dead Zone
- Naming Rules und Best Practices
Im nächsten Tutorial lernst du Datentypen und Type Casting – welche Arten von Daten JavaScript kennt und wie sie konvertiert werden.
Weiterführende Ressourcen
Tipp: Experimentiere in der Browser-Console mit verschiedenen Scope-Szenarien, um das Verhalten zu verinnerlichen!