let
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2016.
Die let
-Deklaration deklariert neu zuweisbare, blockscoped lokale Variablen und initialisiert optional jede mit einem Wert.
Probieren Sie es aus
let x = 1;
if (x === 1) {
let x = 2;
console.log(x);
// Expected output: 2
}
console.log(x);
// Expected output: 1
Syntax
let name1;
let name1 = value1;
let name1 = value1, name2 = value2;
let name1, name2 = value2;
let name1 = value1, name2, /* …, */ nameN = valueN;
Parameter
nameN
-
Der Name der zu deklarierenden Variable. Jeder muss ein legaler JavaScript-Bezeichner oder ein Destructuring Binding Pattern sein.
valueN
Optional-
Anfangswert der Variablen. Es kann jeder legale Ausdruck sein. Standardwert ist
undefined
.
Beschreibung
Der Gültigkeitsbereich einer mit let
deklarierten Variable ist eine der folgenden geschweiften Klammern umschlossenen Syntaxen, die die let
-Deklaration am nächsten enthält:
- Block-Anweisung
switch
-Anweisungtry...catch
-Anweisung- Körper einer der
for
-Anweisungen, wenn sich daslet
im Header der Anweisung befindet - Funktionskörper
- Statischer Initialisierungsblock
Oder wenn keine der obigen zutrifft:
- Das aktuelle Modul, für Code, der im Modulmodus ausgeführt wird
- Der globale Gültigkeitsbereich, für Code, der im Skriptmodus ausgeführt wird.
Im Vergleich zu var
weisen let
-Deklarationen die folgenden Unterschiede auf:
-
let
-Deklarationen sind auf Blöcke sowie Funktionen begrenzt. -
let
-Deklarationen können nur nach Erreichen der Deklarationsstelle zugegriffen werden (siehe temporal dead zone). Aus diesem Grund werdenlet
-Deklarationen allgemein als nicht-hoisted betrachtet. -
let
-Deklarationen erzeugen keine Eigenschaften aufglobalThis
, wenn sie auf oberster Ebene eines Skripts deklariert werden. -
let
-Deklarationen können nicht durch eine andere Deklaration im selben Gültigkeitsbereich erneut deklariert werden. -
let
beginnt Deklarationen, nicht Anweisungen. Das bedeutet, dass Sie eine einzelnelet
-Deklaration nicht als den Körper eines Blocks verwenden können (was sinnvoll ist, da es keinen Zugang zur Variablen gibt).jsif (true) let a = 1; // SyntaxError: Lexical declaration cannot appear in a single-statement context
Beachten Sie, dass let
als Bezeichnername erlaubt ist, wenn es mit var
oder function
im nicht-strikten Modus deklariert wird, aber Sie sollten vermeiden, let
als Bezeichnernamen zu verwenden, um unerwartete Syntaxzweideutigkeiten zu verhindern.
Viele Stilrichtlinien (einschließlich der MDN-Richtlinien) empfehlen die Verwendung von const
über let
, wann immer eine Variable in ihrem Gültigkeitsbereich nicht neu zugewiesen wird. Dies macht deutlich, dass sich der Typ (oder der Wert im Fall eines Primitiven) einer Variablen niemals ändern kann. Andere ziehen let
für Nicht-Primitiven vor, die verändert werden.
Die Liste, die dem Schlüsselwort let
folgt, wird als binding list bezeichnet und ist durch Kommata getrennt, wobei die Kommata nicht die Komma-Operatoren und die =
-Zeichen nicht die Zuweisungsoperatoren sind. Initialisierer späterer Variablen können sich auf frühere Variablen in der Liste beziehen.
Temporale Totzone (TDZ)
Eine mit let
, const
oder class
deklarierte Variable befindet sich von Anfang des Blocks an in einer sogenannten "temporalen Totzone" (TDZ), bis der Code den Punkt erreicht, an dem die Variable deklariert und initialisiert wird.
Während sich die Variable in der TDZ befindet, wurde sie nicht mit einem Wert initialisiert, und jeder Versuch, auf sie zuzugreifen, führt zu einem ReferenceError
. Die Variable wird mit einem Wert initialisiert, wenn die Ausführung den Punkt im Code erreicht, an dem sie deklariert wurde. Wenn kein Anfangswert bei der Variablendeklaration angegeben wurde, wird sie mit einem Wert von undefined
initialisiert.
Dies unterscheidet sich von var
-Variablen, die einen Wert von undefined
zurückgeben, wenn auf sie zugegriffen wird, bevor sie deklariert werden. Der folgende Code zeigt das unterschiedliche Ergebnis, wenn let
und var
im Code aufgerufen werden, bevor sie deklariert werden.
{
// TDZ starts at beginning of scope
console.log(bar); // "undefined"
console.log(foo); // ReferenceError: Cannot access 'foo' before initialization
var bar = 1;
let foo = 2; // End of TDZ (for foo)
}
Der Begriff "temporal" wird verwendet, weil die Zone von der Ausführungsreihenfolge (Zeit) statt von der Schreibordnung des Codes (Position) abhängt. Zum Beispiel funktioniert der unten stehende Code, weil die Funktion, die die let
-Variable verwendet, außerhalb der TDZ aufgerufen wird, auch wenn sie vor der Deklaration erscheint.
{
// TDZ starts at beginning of scope
const func = () => console.log(letVar); // OK
// Within the TDZ letVar access throws `ReferenceError`
let letVar = 3; // End of TDZ (for letVar)
func(); // Called outside TDZ!
}
Die Verwendung des typeof
-Operators für eine Variable in ihrer TDZ wird einen ReferenceError
auslösen:
{
typeof i; // ReferenceError: Cannot access 'i' before initialization
let i = 10;
}
Dies unterscheidet sich von der Verwendung von typeof
für nicht deklarierte Variablen und Variablen, die einen Wert von undefined
haben:
console.log(typeof undeclaredVariable); // "undefined"
Hinweis:>let
- und const
-Deklarationen werden nur verarbeitet, wenn das aktuelle Skript verarbeitet wird. Wenn Sie zwei <script>
-Elemente im Skriptmodus innerhalb eines HTML ausführen, unterliegt das erste Skript nicht den TDZ-Einschränkungen für top-level let
- oder const
-Variablen, die im zweiten Skript deklariert sind, obwohl die erneute Deklaration einer let
- oder const
-Variablen im ersten Skript im zweiten Skript einen Erklärungsfehler verursachen wird.
Erklärungsänderungen
let
-Deklarationen können nicht im selben Gültigkeitsbereich wie jede andere Deklaration sein, einschließlich let
, const
, class
, function
, var
, und import
-Deklarationen.
{
let foo;
let foo; // SyntaxError: Identifier 'foo' has already been declared
}
Eine let
-Deklaration innerhalb eines Funktionskörpers kann nicht denselben Namen wie ein Parameter haben. Eine let
-Deklaration innerhalb eines catch
-Blocks kann nicht denselben Namen wie der catch
-gebundene Bezeichner haben.
function foo(a) {
let a = 1; // SyntaxError: Identifier 'a' has already been declared
}
try {
} catch (e) {
let e; // SyntaxError: Identifier 'e' has already been declared
}
Wenn Sie in einem REPL experimentieren, wie der Firefox-Webkonsole (Werkzeuge > Web-Entwickler > Webkonsole), und Sie führen zwei let
-Deklarationen mit demselben Namen in zwei separaten Eingaben aus, könnten Sie denselben Neudeklarationsfehler erhalten. Siehe weitere Diskussion zu diesem Thema im Firefox-Bug 1580891. Die Chrome-Konsole erlaubt let
-Neudeklarationen zwischen verschiedenen REPL-Eingaben.
Sie könnten Fehler in switch
-Anweisungen begegnen, da es nur einen Block gibt.
let x = 1;
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // SyntaxError: Identifier 'foo' has already been declared
break;
}
Um den Fehler zu vermeiden, umwickeln Sie jeden case
in eine neue Blockanweisung.
let x = 1;
switch (x) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}
Beispiele
Gültigkeitsbereichsregeln
Variablen, die mit let
deklariert werden, haben ihren Gültigkeitsbereich in dem Block, für den sie deklariert werden, sowie in allen enthaltenen Unterblöcken. Auf diese Weise funktioniert let
sehr ähnlich wie var
. Der Hauptunterschied ist, dass der Gültigkeitsbereich einer var
-Variablen die gesamte umschließende Funktion ist:
function varTest() {
var x = 1;
{
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
{
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
Auf der obersten Ebene von Programmen und Funktionen erzeugt let
, im Gegensatz zu var
, keine Eigenschaft im globalen Objekt. Zum Beispiel:
var x = "global";
let y = "global";
console.log(this.x); // "global"
console.log(this.y); // undefined
TDZ kombiniert mit lexikalischem Scoping
Der folgende Code führt zu einem ReferenceError
in der gezeigten Zeile:
function test() {
var foo = 33;
if (foo) {
let foo = foo + 55; // ReferenceError
}
}
test();
Der if
-Block wird evaluiert, weil die äußere var foo
einen Wert hat. Auf Grund des lexikalischen Scopings ist dieser Wert jedoch innerhalb des Blocks nicht verfügbar: Der Bezeichner foo
innerhalb des if
-Blocks ist das let foo
. Der Ausdruck foo + 55
löst einen ReferenceError
aus, weil die Initialisierung von let foo
nicht abgeschlossen ist und er sich noch in der temporalen Totzone befindet.
Dieses Phänomen kann in einer Situation wie der folgenden verwirrend sein. Die Anweisung let n of n.a
befindet sich bereits im Gültigkeitsbereich des Blocks der for...of
-Schleife. So wird der Bezeichner n.a
auf die Eigenschaft a
des Objekts n
im ersten Teil der Anweisung selbst (let n
) aufgelöst. Diese befindet sich noch in der temporalen Totzone, da die Deklarationsanweisung noch nicht erreicht und abgeschlossen wurde.
function go(n) {
// n here is defined!
console.log(n); // { a: [1, 2, 3] }
for (let n of n.a) {
// ^ ReferenceError
console.log(n);
}
}
go({ a: [1, 2, 3] });
Andere Situationen
Wenn let
innerhalb eines Blocks verwendet wird, beschränkt es den Gültigkeitsbereich der Variablen auf diesen Block. Beachten Sie den Unterschied zu var
, dessen Gültigkeitsbereich innerhalb der Funktion ist, in der es deklariert wird.
var a = 1;
var b = 2;
{
var a = 11; // the scope is global
let b = 22; // the scope is inside the block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
Diese Kombination von var
- und let
-Deklarationen unten ist jedoch ein SyntaxError
, weil var
nicht block-scoped ist, was dazu führt, dass sie sich im selben Gültigkeitsbereich befinden. Dies führt zu einer impliziten Neudeklaration der Variablen.
let x = 1;
{
var x = 2; // SyntaxError for re-declaration
}
Deklaration mit Destructuring
Die linke Seite jedes =
kann auch ein Binding-Pattern sein. Dies ermöglicht die Erstellung mehrerer Variablen auf einmal.
const result = /(a+)(b+)(c+)/.exec("aaabcc");
let [, a, b, c] = result;
console.log(a, b, c); // "aaa" "b" "cc"
Für weitere Informationen siehe Destructuring.
Spezifikationen
Specification |
---|
ECMAScript® 2026 Language Specification # sec-let-and-const-declarations |
Browser-Kompatibilität
Siehe auch
var
const
- Hoisting
- ES6 In Depth:
let
andconst
auf hacks.mozilla.org (2015) - Breaking changes in
let
andconst
in Firefox 44 auf blog.mozilla.org (2015) - You Don't Know JS: Scope & Closures, Ch.3: Function vs. Block Scope von Kyle Simpson
- What is the Temporal Dead Zone? auf Stack Overflow
- What is the difference between using
let
andvar
? auf Stack Overflow - Why was the name 'let' chosen for block-scoped variable declarations in JavaScript? auf Stack Overflow