Signatur
Beschreibung
Die let-Deklaration deklariert wiederzuweisbare, blockskopierte lokale Variablen und initialisiert jede optional mit einem Wert.
Der Gültigkeitsbereich einer mit let deklarierten Variablen ist eine der folgenden von geschweiften Klammern umschlossenen Syntaxen, die die let-Deklaration am nächsten enthält:
- Block-Anweisung
switch-Anweisungtry...catch-Anweisung- Rumpf einer der
for-Anweisungen, falls dasletim Kopf der Anweisung steht - Funktionsrumpf
- Static initialization block
Oder, falls keines der obigen zutrifft:
- Das aktuelle module, für Code, der im Modul-Modus läuft
- Der globale Scope, für Code, der im Script-Modus läuft.
Im Vergleich zu var haben let-Deklarationen die folgenden Unterschiede:
let-Deklarationen sind auf Blöcke sowie auf Funktionen beschränkt.- Auf
let-Deklarationen kann erst zugegriffen werden, nachdem die Stelle der Deklaration erreicht wurde (siehe temporal dead zone). Aus diesem Grund werdenlet-Deklarationen üblicherweise als non-hoisted betrachtet. let-Deklarationen erzeugen keine Eigenschaften aufglobalThis, wenn sie auf der obersten Ebene eines Scripts deklariert werden.let-Deklarationen können nicht durch eine andere Deklaration im selben Scope erneut deklariert werden.letbeginnt Deklarationen, keine Anweisungen. Das bedeutet, dass eine alleinstehendelet-Deklaration nicht als Rumpf eines Blocks verwendet werden kann (was sinnvoll ist, da es keine Möglichkeit gäbe, auf die Variable zuzugreifen).
Beachte, dass let als Identifier-Name erlaubt ist, wenn es mit var oder function im non-strict mode deklariert wird, du solltest jedoch die Verwendung von let als Identifier-Name vermeiden, um unerwartete Syntax-Mehrdeutigkeiten zu verhindern.
Viele Style Guides (einschließlich des MDN-Style-Guides) empfehlen, const gegenüber let zu verwenden, wann immer einer Variablen in ihrem Scope kein neuer Wert zugewiesen wird. Dies verdeutlicht die Absicht, dass sich der Typ (oder der Wert im Falle eines primitiven Werts) einer Variablen niemals ändern kann. Andere bevorzugen möglicherweise let für Nicht-Primitives, die mutiert werden.
Die Liste, die auf das Schlüsselwort let folgt, wird binding list genannt und ist durch Kommas getrennt, wobei die Kommas keine Komma-Operatoren und die =-Zeichen keine Zuweisungsoperatoren sind. Initialisierer späterer Variablen können sich auf frühere Variablen in der Liste beziehen.
Temporal dead zone (TDZ)
Eine mit let, const oder class deklarierte Variable befindet sich in einer sogenannten "temporal dead zone" (TDZ) vom Beginn des Blocks bis zu dem Punkt, an dem die Codeausführung die Stelle erreicht, an der die Variable deklariert und initialisiert wird.
Solange sie sich in der TDZ befindet, wurde die Variable nicht mit einem Wert initialisiert, und jeder Zugriffsversuch führt zu einem ReferenceError. Die Variable wird mit einem Wert initialisiert, wenn die Ausführung die Stelle im Code erreicht, an der sie deklariert wurde. Wenn bei der Variablendeklaration kein Anfangswert angegeben wurde, wird sie mit dem Wert undefined initialisiert.
Dies unterscheidet sich von hoisted var-Variablen, die den Wert undefined zurückgeben, wenn auf sie zugegriffen wird, bevor sie deklariert wurden. Der folgende Code demonstriert das unterschiedliche Ergebnis, wenn let und var im Code vor der Stelle, an der sie deklariert werden, angesprochen werden.
Der Begriff "temporal" wird verwendet, weil die Zone von der Ausführungsreihenfolge (Zeit) und nicht von der Reihenfolge, in der der Code geschrieben wurde (Position), abhängt. Zum Beispiel funktioniert der folgende Code, weil, obwohl die Funktion, die die let-Variable verwendet, vor der Deklaration der Variablen erscheint, die Funktion außerhalb der TDZ aufgerufen wird.
Die Verwendung des typeof-Operators für eine Variable innerhalb ihrer TDZ wirft einen ReferenceError.
Dies unterscheidet sich von der Verwendung von typeof für undeklarierte Variablen und Variablen, die den Wert undefined halten.
Redeclarations
let-Deklarationen können nicht im selben Scope wie andere Deklarationen stehen, einschließlich let-, const-, class-, function-, var- und import-Deklarationen.
Eine let-Deklaration innerhalb eines Funktionsrumpfes darf nicht denselben Namen wie ein Parameter haben. Eine let-Deklaration innerhalb eines catch-Blocks darf nicht denselben Namen wie der an catch gebundene Identifier haben.
Wenn du in einer REPL experimentierst, wie z. B. der Firefox Web Console (Tools > Web Developer > Web Console), und zwei let-Deklarationen mit demselben Namen in zwei separaten Eingaben ausführst, kann derselbe Redeclaration-Fehler auftreten. Die Chrome-Konsole erlaubt let-Redeklarationen zwischen verschiedenen REPL-Eingaben.
In switch-Anweisungen können Fehler auftreten, weil es nur einen Block gibt. Um den Fehler zu vermeiden, umschließe jedes case mit einer neuen Block-Anweisung.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $nameN Pflicht | identifier | — | Der Name der zu deklarierenden Variablen. Jeder Name muss ein gültiger JavaScript-Identifier oder ein destructuring binding pattern sein. |
| $valueN | expression | undefined | Anfangswert der Variablen. Es kann jeder gültige Ausdruck sein. Der Standardwert ist undefined. |
Rückgabewert
Beispiele
Scoping-Regeln
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
}
let erzeugt keine globale Objekteigenschaft
var x = "global";
let y = "global";
console.log(this.x); // "global"
console.log(this.y); // undefined
TDZ kombiniert mit lexikalischem Scoping
function test() {
var foo = 33;
if (foo) {
let foo = foo + 55; // ReferenceError
}
}
test();
TDZ in for...of
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] });
TDZ-Beispiel mit var und let
{
// 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)
}
TDZ ist temporal (nicht positional)
{
// 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!
}
typeof in der TDZ
{
typeof i; // ReferenceError: Cannot access 'i' before initialization
let i = 10;
}
typeof für undeklarierte Variablen
console.log(typeof undeclaredVariable); // "undefined"
Redeklaration im selben Scope
{
let foo;
let foo; // SyntaxError: Identifier 'foo' has already been declared
}
Konflikt mit Parameter oder catch-Identifier
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
}
let in switch (Fehler)
let x = 1;
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // SyntaxError: Identifier 'foo' has already been declared
break;
}
let in switch (mit Block-Statements)
let x = 1;
switch (x) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}
Weitere Situationen: var vs let
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
Implizite Re-Deklaration mit var
let x = 1;
{
var x = 2; // SyntaxError for re-declaration
}
Deklaration mit Destructuring
const result = /(a+)(b+)(c+)/.exec("aaabcc");
let [, a, b, c] = result;
console.log(a, b, c); // "aaa" "b" "cc"
// Wichtig · Fallstricke
Hinweis: let- und const-Deklarationen werden nur verarbeitet, wenn das aktuelle Script verarbeitet wird. Wenn du zwei <script>-Elemente im Script-Modus in einem HTML hast, unterliegt das erste Script nicht den TDZ-Einschränkungen für auf oberster Ebene deklarierte let- oder const-Variablen aus dem zweiten Script. Wenn du jedoch eine let- oder const-Variable im ersten Script deklarierst, verursacht ein erneutes Deklarieren im zweiten Script einen Redeclaration-Fehler.