let
Die let
Deklaration deklariert neu zuweisbare, block-skopierte lokale Variablen und initialisiert optional jede mit einem Wert.
Probieren Sie es aus
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 Name muss ein gültiger JavaScript-Bezeichner oder ein Destructuring-Bindungsmuster sein.
valueN
Optional-
Anfangswert der Variable. Es kann jeder gültige Ausdruck sein. Standardwert ist
undefined
.
Beschreibung
Der Gültigkeitsbereich einer mit let
deklarierten Variablen ist eine der folgenden geschweifte Klammern umschließenden Syntaxen, die die let
-Deklaration am nächsten enthält:
- Block Anweisung
switch
Anweisungtry...catch
Anweisung- Körper einer der
for
-Anweisungen, wenn daslet
sich im Kopf der Anweisung befindet - Funktionskörper
- Statische Initialisierungsblöcke
Oder wenn keiner der obigen Punkte zutrifft:
- Das aktuelle Modul, für Code, der im Modulmodus läuft
- Der globale Bereich, für Code, der im Skriptmodus läuft.
Im Vergleich mit var
weisen let
-Deklarationen die folgenden Unterschiede auf:
-
let
-Deklarationen sind auf Blöcke sowie auf Funktionen beschränkt. -
let
-Deklarationen können erst nach Erreichen der Deklarationsstelle zugegriffen werden (siehe temporal dead zone). Aus diesem Grund werdenlet
-Deklarationen häufig als nicht-geliftet betrachtet. -
let
-Deklarationen erzeugen keine Eigenschaften aufglobalThis
, wenn sie auf der obersten Ebene eines Skripts deklariert sind. -
let
-Deklarationen können im gleichen Bereich durch keine andere Deklaration neu deklariert werden. -
let
beginnt Deklarationen, nicht Anweisungen. Das bedeutet, dass Sie eine einzelnelet
-Deklaration nicht als Körper eines Blocks verwenden können (was Sinn macht, da es keinen Weg gibt, auf die Variable zuzugreifen).jsif (true) let a = 1; // SyntaxError: Lexical declaration cannot appear in a single-statement context
Beachten Sie, dass let
als Bezeichnername erlaubt ist, wenn er mit var
oder function
im nicht-strengen Modus deklariert wird, aber man sollte let
als Bezeichnername vermeiden, um unerwartete Syntaxzweideutigkeiten zu vermeiden.
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 die Absicht klar, dass der Typ (oder der Wert, im Fall eines Primitivs) einer Variablen niemals geändert werden kann. Andere bevorzugen möglicherweise let
für Nicht-Primitiven, die verändert werden.
Die Liste, die dem let
-Schlüsselwort folgt, wird Binding- Liste genannt und durch Kommata getrennt, wobei die Kommata keine Kommaoperatoren und die =
-Zeichen keine Zuweisungsoperatoren sind. Initialisierungen 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 in einer "temporalen Totzone" (TDZ) vom Beginn des Blocks bis der Codeausführung die Deklarationsstelle der Variable erreicht und initialisiert.
Innerhalb der TDZ ist die Variable noch 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 Codeausführung die Deklarationsstelle erreicht. Wenn kein Anfangswert bei der Variablendeklaration angegeben wurde, wird sie mit dem Wert undefined
initialisiert.
Dies unterscheidet sich von var
-Variablen, die einen Wert von undefined
zurückgeben, wenn auf sie zugegriffen wird, bevor sie deklariert sind. Der Code unten zeigt die unterschiedlichen Ergebnisse, wenn let
und var
im Code aufgerufen werden, bevor sie deklariert sind.
{
// 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) abhängt und nicht von der Reihenfolge, in der der Code geschrieben ist (Position). Zum Beispiel funktioniert der untenstehende Code, weil, obwohl die Funktion, die die let
-Variable verwendet, vor der Deklaration der Variablen erscheint, die Funktion außerhalb der TDZ aufgerufen wird.
{
// 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!
}
Das Verwenden des Operators typeof
für eine Variable in ihrer TDZ wird einen ReferenceError
werfen:
{
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"
Note:
let
- undconst
-Deklarationen werden nur verarbeitet, wenn das aktuelle Skript verarbeitet wird. Wenn Sie zwei<script>
-Elemente im Skriptmodus innerhalb eines HTML-Dokuments ausführen, unterliegt das erste Skript nicht den TDZ-Einschränkungen für oberstelet
- oderconst
-Variablen, die im zweiten Skript deklariert sind, obwohl eine Deklaration vonlet
oderconst
im ersten Skript in einer Neudeklarationsfehler resultiert, wenn sie im zweiten Skript erneut deklariert wird.
Neudeklarationen
let
-Deklarationen können nicht im gleichen Bereich mit einer anderen Deklaration, einschließlich let
, const
, class
, function
, var
, und import
deklariert werden.
{
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 z.B. der Firefox-Webkonsole (Tools > Web Developer > Webkonsole), und Sie führen zwei let
Deklarationen mit demselben Namen in zwei separaten Eingaben aus, können Sie denselben Neudeklarationsfehler erhalten. Siehe weitere Diskussion dieses Problems in Firefox Bug 1580891. Die Chrome-Konsole erlaubt let
Neudeklarationen zwischen verschiedenen REPL-Eingaben.
Sie können auf Fehler in switch
-Anweisungen stoßen, da es derzeit 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 innerhalb des Blocks, für den sie deklariert sind, sowie in allen darin enthaltenen Unterblöcken. Auf diese Weise funktioniert let
sehr ähnlich wie var
. Der Hauptunterschied besteht darin, dass der Gültigkeitsbereich einer var
-Variablen die gesamte umgebende 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 erstellt 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 lexikalischer Bereichsszedierung
Der folgende Code führt an der gezeigten Zeile zu einem ReferenceError
:
function test() {
var foo = 33;
if (foo) {
let foo = foo + 55; // ReferenceError
}
}
test();
Der if
-Block wird ausgewertet, weil das äußere var foo
einen Wert hat. Aufgrund der lexikalischen Bereichslogik 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
wirft einen ReferenceError
, weil die Initialisierung von let foo
nicht abgeschlossen ist - es befindet sich noch in der Temporalen Totzone.
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 Blockes der for...of
Schleife. Daher wird der Bezeichner n.a
auf die Eigenschaft a
des n
Objekts im ersten Teil der Anweisung selbst (let n
) aufgelöst. Dies befindet sich noch in der Temporalen Totzone da ihre Deklaration noch nicht erreicht und beendet 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 liegt, in der es deklariert ist.
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 führt jedoch zu einem SyntaxError
, weil var
nicht blockskopiert ist und sie sich im gleichen Bereich 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 Bindungsmuster sein. Dies ermöglicht das Erstellen mehrerer Variablen gleichzeitig.
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-Zuweisung.
Spezifikationen
Specification |
---|
ECMAScript Language Specification # sec-let-and-const-declarations |
Browser-Kompatibilität
BCD tables only load in the browser
Siehe auch
var
const
- Hoisting
- ES6 In Depth:
let
undconst
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