Var, let und const in JavaScript: Das infernale Trio erklärt (mit einem Hauch von TypeScript)
Hallo, du JavaScript-Entwickler, der sich die Haare über diese Variablen rauft! Fragst du dich, wann du var, let oder const verwenden sollst, ohne dich in Teambesprechungen zu blamieren? Bleib dran, wir werden das gemeinsam ruhig und mit einem Lächeln klären. Auf dem Programm: Wir erkunden jedes Schlüsselwort, vergleichen ihre Scopes (global, Funktion, Block), lachen ein bisschen über Hoisting (diesen etwas magischen JavaScript-Mechanismus), werfen praktische Beispiele ein und beenden mit einem Hauch von TypeScript. Bereit? Los geht's!
Das var-Schlüsselwort: Der unberechenbare Vorfahre
Beginnen wir mit var, dem Ältesten der JavaScript-Variablen. Wenn JavaScript eine TV-Serie wäre, wäre var dieser Old-School-Charakter, unberechenbar aber liebenswert. Bis ES5 war es alles, was wir hatten, um unsere Variablen zu deklarieren. Du kannst es heute noch verwenden, aber Vorsicht: Es hat einige Eigenheiten, die dich überraschen könnten.
Eigenschaften von var
- Scope von var: Eine mit var deklarierte Variable ist auf die Funktion beschränkt, die sie enthält (oder global, wenn außerhalb einer Funktion deklariert). Sie ignoriert Block-Klammern (if, for, etc.). Kurz gesagt, ein var, das in einem Block deklariert wurde, bleibt außerhalb des Blocks zugänglich, solange wir uns in derselben Funktion befinden.
- Neudeklaration erlaubt: Mit var kannst du dieselbe Variable mehrmals im selben Scope ohne Fehler deklarieren. Zum Beispiel:
var x = 1; var x = 2;löst keinen Fehler aus – JavaScript überschreibt einfach den ersten Wert mit dem zweiten. Praktisch für Legacy-Code, aber eine Quelle der Verwirrung, die in neuem Code vermieden werden sollte.
Um den übermäßig breiten Scope von var zu veranschaulichen, hier ein kleines Beispiel:
javascript
Ja, obwohl dieses fruit innerhalb einer if-Anweisung deklariert wurde, zeigt der console.log außerhalb des Blocks es ohne Probleme an. var kümmert sich nicht um Block-Grenzen: Es ist entweder global oder an seine enthaltende Funktion gebunden, Punkt.
Und das Beste (oder Schlimmste) zum Schluss: Hoisting. Auf Deutsch nennen wir es manchmal "Anheben", aber seien wir ehrlich, wir verwenden meistens den Begriff Hoisting. Es ist vars Tendenz, sich leise am Anfang des Scopes zu deklarieren. JavaScript verhält sich während der Ausführung so, als würden alle var-Deklarationen an den Anfang der Funktion "angehoben". Dadurch kannst du deine Variable vor ihrer Deklarationszeile verwenden... mit einem etwas seltsamen Standardwert. Schauen wir uns das im Hoisting-Abschnitt genauer an (Spoiler: var überrascht dich gerne mit undefined).
Zusammenfassend hat var uns gute Dienste geleistet, aber es ist etwas hinterhältig an den Rändern: breiter Scope, stille Neudeklaration, unberechenbares Hoisting... Wir können es besser machen, und zum Glück hat ES6 neue Schlüsselwörter eingeführt, um Ordnung in das Chaos zu bringen!
Das let-Schlüsselwort: Die gut erzogene neue Variable
2015 begrüßte JavaScript let (zusammen mit const). Und da bekamen wir ein kleines Variablen-Makeover. let ist wie das coole, disziplinierte Kind: Es behebt die meisten Eigenheiten von var und bleibt dabei flexibel.
Eigenschaften von let
- Scope von let: Eine mit let deklarierte Variable ist auf den Block beschränkt, in dem sie definiert ist. Ein Block ist alles zwischen { ... } – ob es eine Funktion, eine if-Anweisung, eine for-Schleife etc. ist. Wenn du ein let innerhalb eines Blocks deklarierst, existiert es außerhalb nicht. Endlich etwas Ordnung! Keine Variablen mehr, die ohne Erlaubnis aus if-Anweisungen oder Schleifen entkommen.
- Keine Neudeklaration: Im Gegensatz zu var kannst du dieselbe let-Variable nicht zweimal im selben Scope deklarieren. Wenn du versuchst,
let x = 1; let x = 2;im selben Block zu machen, bekommst du einen schönenSyntaxError: Identifier 'x' has already been declared. Das vermeidet viel Verwirrung, gib es zu.
Um den Scope-Unterschied zu var deutlich zu sehen, vergleichen wir mit dem vorherigen Beispiel, indem wir var durch let ersetzen:
javascript
Mit let, sobald du aus den geschweiften Klammern der if-Anweisung heraus bist, ist es das, die vegetable-Variable ist nicht mehr definiert. Versuche, sie zu loggen, und bam: ReferenceError. Das ist let, das gutes Scoping-Verhalten durchsetzt.
Und was ist mit Hoisting? let-Variablen (und const) werden auch gehoistet, aber anders. Sie sind nicht verwendbar, bevor sie deklariert wurden. Technisch weiß die JS-Engine, dass sie im Block existieren (sie reserviert den Speicher), aber bis die Deklarationszeile ausgeführt wird, löst jeder Zugriffsversuch einen Fehler aus. Wir sagen, diese Variablen sind in der Temporal Dead Zone (ja, es klingt wie ein Horrorfilm, aber es ist nur der schicke Name für "vor der Initialisierung nicht zugänglich"). Wir werden dieses Verhalten später genauer besprechen, aber merk dir, dass let dich nicht wild eine Variable zu früh verwenden lässt.
In der Praxis ist let zur Standardwahl für Variablen geworden, die sich im Laufe der Zeit ändern werden. Es bringt Klarheit (Block-Scope) und Sicherheit (keine versehentliche Neudeklaration, kein Zugriff vor der Deklaration). Kurz gesagt, let ist dein neuer Freund für die Deklaration temporärer oder veränderbarer Variablen.
Das const-Schlüsselwort: Die sichere Wette (aber nicht eingefroren)
Jetzt zu const! Zur gleichen Zeit wie let eingeführt, erstellt dieses Schlüsselwort Konstanten... oder fast. Sagen wir, es erstellt Variablen, deren Referenz sich nicht ändern wird. const hat denselben Block-Scope wie let (keine mehr herumwandernden vars) und dieselben Hoisting-Regeln (Temporal Dead Zone bis zur Deklaration). Der große Unterschied ist, dass die Variable nach der Initialisierung nicht neu zugewiesen werden kann.
Eigenschaften von const
- Muss initialisiert werden: Mit const musst du bei der Deklaration einen Wert zuweisen. Keine Wahl.
const x;allein funktioniert nicht (direkter SyntaxError). Du musst zum Beispielconst x = 42;machen. - Keine Neuzuweisung: Sobald deine Konstante definiert ist, gibt es keine Möglichkeit, ihr später einen neuen Wert zu geben. Wenn du es versuchst, bekommst du einen Laufzeitfehler (TypeError mit "assignment to constant variable"). Der Wert ist fest... nun, die Referenz ist fest.
- Block-Scope & keine Neudeklaration: Wie let lebt ein const in dem Block, in dem es deklariert wurde, und du kannst denselben Namen nicht zweimal im selben Scope deklarieren. Es ist sauber.
Schau dir dieses kleine Beispiel an, um den Unterschied zu einer veränderbaren Variable deutlich zu sehen:
javascript
Wir definieren PI als konstant, wir können es ohne Bedenken verwenden, solange wir nicht versuchen, es zu ändern. Wenn wir versuchen, PI = 3.15 zu machen, stoppt uns JavaScript kalt: Keine Änderung einer Konstante.
Hinweis: Konstant bedeutet nicht 100% unveränderlich. Wenn der Wert ein Objekt oder ein Array ist, kannst du immer noch das Innere des Objekts/Arrays ändern. Was sich nicht bewegt, ist die Variable selbst (die Speicherreferenz). Zum Beispiel:
javascript
Hier konnten wir name im user-Objekt trotz const ändern. Allerdings ist eine vollständige Neuzuweisung von user zu einem anderen Objekt verboten. Also, const = konstant, nicht veränderbar, aber nur auf der Variablenebene selbst. Verwechsle nicht Variablenkonstanz mit Wertunveränderlichkeit.
javascript
Bei einem Array ist es die gleiche Logik: Wir können seinen Inhalt ändern (Elemente hinzufügen, löschen, modifizieren), weil wir nur das Innere des Arrays ändern. Aber wir können die fruits-Variable nicht einem neuen Array neu zuweisen. Es ist, als wäre das Array eine Box: Wir können ändern, was drin ist, aber wir können die Box selbst nicht ersetzen.
In der Praxis ist const ideal für alle Werte, die sich nicht ändern sollten: zum Beispiel eine Konfiguration, eine Referenz etc. Es wird häufig verwendet und macht Code robuster (wir wissen, dass diese Variable sich nicht bewegen wird). Tatsächlich empfehlen Best Practices oft, const standardmäßig zu verwenden und nur zu let zu wechseln, wenn wir wissen, dass der Wert sich ändern muss. Was var betrifft... nun, außer in speziellen Fällen vergessen wir es 😉.
Variablen-Scope: global, Funktion oder Block?
Lass uns mehr über Scope sprechen. Scope bestimmt, "wo" eine Variable in deinem Code zugänglich ist. Es gibt hauptsächlich drei Scope-Ebenen in JavaScript:
Arten von Scopes
- Globaler Scope: Eine Variable ist global, wenn sie außerhalb einer Funktion deklariert wird (im Hauptskript oder der Konsole). Sie ist dann überall zugänglich (in jeder Funktion oder jedem Block). ⚠️ Warnung, außerhalb eines Moduls wird ein globales var zu einer Eigenschaft des globalen Objekts (wie window in einem Browser), während let und const "saubere" globale Variablen erstellen (nicht an window gebunden). In einem ES6-Modul lecken Top-Level-Variablen überhaupt nicht auf das globale Objekt.
- Funktions-Scope: Dies ist der Scope, der innerhalb einer Funktion erstellt wird. Ein in einer Funktion deklariertes var ist nur innerhalb dieser Funktion sichtbar (und ihrer Unterfunktionen, falls vorhanden). Wir können es außerhalb nicht sehen. Dasselbe gilt für let und const, die in einer Funktion deklariert wurden: Sie bleiben lokal zu dieser Funktion.
- Block-Scope: Dies ist der Scope, der auf einen Block beschränkt ist, der durch { ... } begrenzt wird (zum Beispiel innerhalb einer if-Anweisung, einer for-Schleife, einer while-Schleife oder einfach einem isolierten Block). let und const sind block-scoped, was bedeutet, dass sie nur in dem Block zugänglich sind, in dem sie definiert sind (und seinen Unterblöcken). var hingegen hat keinen Block-Scope: Sein Referenzblock ist die enthaltende Funktion (oder global, wenn keine Funktion).
Zusammenfassend: var ist auf die Funktion (oder global) beschränkt, während let und const auf den aktuellen Block beschränkt sind. Dieser Unterschied löst viele klassische Fallstricke. Zum Beispiel:
javascript
Hier lässt die Schleife mit var i außen hängen, mit seinem Endwert 3. Die Schleife mit let hingegen räumt j beim Verlassen auf: unmöglich, danach darauf zuzugreifen. In der Praxis bedeutet das, dass du mehrere let-Variablen mit demselben Namen in verschiedenen Blöcken ohne Interferenz haben kannst, wo ein einzelnes var zwischen all diesen Blöcken geteilt worden wäre.
Hoisting: Wenn JavaScript Verstecken spielt
Kommen wir zu Hoisting, diesem Deklarations-Anhebungsmechanismus. Es ist oft eine Quelle der Verwirrung (und Witze in Besprechungen), also lass uns das klären. Hoisting ist, wenn die JavaScript-Engine Variablen- und Funktionsdeklarationen während der Ausführung an den Anfang ihres Scopes "verschiebt". In Wirklichkeit wird in deinem Code nichts wirklich verschoben, es ist nur so, dass JavaScript den Speicher für deine Variablen im Voraus allokiert, bevor es Schritt für Schritt ausführt.
Hoisting-Verhalten
- Für var: Die Deklaration wird gehoistet UND standardmäßig mit undefined initialisiert. Du kannst also absolut eine var-Variable vor ihrer Deklarationszeile verwenden, sie existiert bereits (mit dem Wert undefined, bis die echte Zuweisung später kommt). Es ist ein legitimes Sprachverhalten, aber es kann ziemlich hinterhältige Bugs verursachen, wenn du nicht aufpasst.
- Für let und const: Die Deklaration wird auch gehoistet (die Engine weiß, dass es eine Variable in diesem Block gibt), aber es wird keine Standardinitialisierung durchgeführt. Die Variable wird in die Temporal Dead Zone platziert, bis die Deklarationszeile ausgeführt wird. In der Praxis bedeutet das, dass wenn du versuchst, diese Variable vor ihrer tatsächlichen Deklaration zu lesen oder zu verwenden, JavaScript einen Fehler werfen wird (ReferenceError). Mit anderen Worten, die Variable existiert in der Theorie, aber du kannst nicht darauf zugreifen, bis ihre Deklaration/Initialisierung ausgeführt wurde.
Lass uns einen kleinen Hoisting-Test in der Praxis machen:
javascript
Zum Zeitpunkt des ersten console.log wurde die myVar-Variable tatsächlich über Hoisting im Speicher erstellt, aber ihr Standardwert ist undefined (da wir sie noch nicht zugewiesen haben). Kein Fehler, nur undefined wird angezeigt. Dann weisen wir "Hallo" zu, und beim zweiten Mal bekommen wir den erwarteten Wert.
Jetzt schauen wir uns das mit let an:
javascript
Hier löst der erste console.log einen ReferenceError aus. Warum? Weil myLet ohne Initialisierung gehoistet wird. Es ist in seiner Temporal Dead Zone, unzugänglich. JavaScript weigert sich, uns einen Wert zu geben, der noch nicht wirklich existiert. Sobald wir let myLet = "Hallo"; ausführen, kommt die Variable aus ihrer Dead Zone und bekommt "Hallo". Der zweite console.log funktioniert dann perfekt.
Wir können es deutlich sehen: var verhält sich wie ein Ninja, indem es seine Deklaration nach oben hebt und sich leise den Wert undefined gibt, während let/const auf Nummer sicher gehen und jede Verwendung verhindern, bis sie initialisiert sind. Moral der Geschichte: Vermeide es, Code zu schreiben, der sich auf Hoisting verlässt, es ist ein Rezept für Gehirnknoten (und unerwartete undefineds). Besser, deine Variablen am Anfang ihrer Scopes zu deklarieren und deinen Code klar zu halten. Wenn du es vergisst, wird dich das Verhalten von let/const mit einem Fehler daran erinnern, wo var dich mit einem undefined hätte herumstochern lassen.
Ah, und während wir dabei sind, beachte, dass klassisch deklarierte Funktionen (function myFunction() \{ ... \}) auch vollständig gehoistet werden. Du kannst eine Funktion aufrufen, die später in deinem Code deklariert ist, JavaScript wird sie bereits kennen. Aber Vorsicht, Pfeilfunktionen oder Funktionsausdrücke, die Variablen zugewiesen werden, folgen den Hoisting-Regeln von var/let entsprechend dem verwendeten Schlüsselwort (ein Thema für einen anderen Tag 😉).
Ein kurzer Abstecher durch TypeScript: Noch mehr Klarheit
Bevor wir uns verabschieden, lass uns kurz über TypeScript sprechen. Wenn du anfängst, TypeScript zu verwenden (das Super-Set von JavaScript, das statische Typisierung hinzufügt), wirst du unsere drei Freunde var, let und const wiederfinden. Gute Nachricht: Ihre Scope- und Hoisting-Verhalten bleiben genau gleich wie in purem JavaScript, da TypeScript in Standard-JavaScript kompiliert wird. Allerdings bringt TypeScript seine persönliche Note zur Typisierung, und das ist einen Blick wert, besonders für let und const.
TypeScript und Variablen
- Typhinferenz: TypeScript erratet den Typ deiner Variablen basierend auf dem Anfangswert. Wenn du
let fruit = "Apfel";schreibst, wird TypeScript ableiten, dass fruit vom Typ string ist. Wenn dulet age = 25;schreibst, wird es verstehen, dass age eine Zahl ist, etc. Für let bleibt es ziemlich breit: Die Variable kann sich ändern, also ist der Typ der grundlegende (string, number, etc.). - Konstanten und Literaltypen: Wo es interessant wird, ist, dass TypeScript mit const einen Literaltyp ableiten wird. Mit anderen Worten, da der Wert konstant ist, kann sich TS leisten zu sagen "diese Variable hat genau diesen Wert als ihren Typ". Zum Beispiel:
typescript
Die color-Variable ist vom Typ "rot" und nicht nur string. Vorteil? Wenn dein Code später genau den Wert "rot" oder "blau" erwartet (zum Beispiel ein Parameter, der nur einer dieser Farben sein kann), und du const color = "rot" hast, kannst du ihn ohne Bedenken übergeben. Mit einem let color = "rot" (breiter String-Typ) hätte TypeScript sich beschwert, weil "rot" nur eine Möglichkeit unter allen Strings ist. Kurz gesagt, const in TypeScript ermöglicht ultra-präzise Typisierung, wenn es nützlich ist. Es ist wie ein Bonus, der das Konzept der Konstante weiter verstärkt.
- Gleiche Disziplin: TypeScript wird dich ermutigen, let und const genau wie in ES6 zu verwenden. Tatsächlich verbieten die meisten TypeScript-Projekte var komplett (es gibt sogar eine Linter-Regel dafür). Und wenn du versuchst, eine Variable vor der Deklaration zu verwenden, wird TypeScript dich zur Kompilierzeit anschreien – lange bevor die JavaScript-Laufzeit es tut. Zum Beispiel, wenn du TypeScript mit
console.log(myVar); var myVar = 3;schreibst, wird es signalisieren, dass du ein Scope- oder Ordnungsproblem hast. Dasselbe für ein zu früh verwendetes let, TS kennt die Hoisting-Regeln und wird dich (soweit möglich) vor Fehlern schützen.
Zusammenfassend ändert TypeScript die grundlegenden Regeln von var/let/const nicht, aber es verstärkt sie mit dem Sicherheitsnetz der Typisierung. Du gewinnst an Klarheit und fängst Fehler früher. Merk dir besonders, dass const in TypeScript doppelt gewinnt: eine nicht neu zuzuweisende Variable und ein präziser Literaltyp – was willst du mehr?
Fazit: Wann was verwenden, ohne sich zu irren
Wir haben alles abgedeckt, also wer ist der Gewinner im var vs let vs const Match? Keine große Überraschung: 2025 gewinnt das let & const Duo haushoch für das Schreiben von sauberem und wartbarem Code. Hier ist eine würzige Zusammenfassung praktischer Ratschläge:
Best Practices
- Verwende const so oft wie möglich: Für jede Variable, deren Wert sich nicht ändern muss, ist const dein bester Freund. Es verriegelt die Neuzuweisung und zeigt allen (einschließlich dir in 6 Monaten) klar an, dass sich dieser Wert nicht bewegen wird. Perfekt für Konfigurationen, feste Referenzen etc.
- Wenn du den Wert ändern musst, verwende let: Brauchst du einen Zähler zu erhöhen, ein Ergebnis zu akkumulieren, einen veränderbaren Zwischenwert zu speichern? let ist dafür da. Es verhält sich gut (Block-Scope, keine unerwarteten Hoisting-Fallen), und es gibt dir die Flexibilität, den Wert zu ändern.
- Vermeide var außer in seltsamen Fällen: Ehrlich gesagt kann var praktisch aus deinem alltäglichen Vokabular verschwinden. Es überlebt aus Gründen der Abwärtskompatibilität und einigen spezifischen Szenarien, aber in modernem Code ist es nicht mehr wirklich in Mode. Wenn du an einem alten Projekt arbeitest oder den globalen Scope absichtlich manipulieren musst (Dinge, die wir generell vermeiden), okay, var könnte sein Gesicht zeigen. Ansonsten kannst du es ins JavaScript-Relikte-Museum stellen 😄.
- Im Zweifelsfall, erkläre dich: Wenn du eines Tages var verwendest und jemand in einer Besprechung fragt warum, habe einen guten Grund und erkläre ihn (zum Beispiel "Ich muss diese Variable global deklarieren, damit alte Skripte darauf zugreifen können"). Aber 99% der Zeit wirst du diese Gymnastik nicht brauchen: let und const werden alle deine Bedürfnisse ohne mit der Wimper zu zucken abdecken.
Da hast du es, du weißt jetzt, wann du var, let oder const in JavaScript verwenden sollst, und sogar ein bisschen, wie es mit TypeScript funktioniert. Keine Verwirrung mehr über unsere drei Begleiter oder Spott in der Code-Review, weil du ein var ohne gültigen Grund aus dem Hut gezogen hast. Geh friedlich coden, und vergiss nicht: const so oft wie möglich, let wenn nötig, und var... so wenig wie möglich! Happy Coding!