Start · Sprachen · JavaScript · Referenz · let

let

Anweisung

Die <code>let</code>-Deklaration deklariert wiederzuweisbare, blockskopierte lokale Variablen, optional mit Anfangswert.

seit JavaScript ES2015 Kategorie: syntax

Signatur

let name1; let name1 = value1; let name1 = value1, name2 = value2; let name1, name2 = value2; let name1 = value1, name2, /* …, */ nameN = valueN;

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-Anweisung
  • try...catch-Anweisung
  • Rumpf einer der for-Anweisungen, falls das let im 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 werden let-Deklarationen üblicherweise als non-hoisted betrachtet.
  • let-Deklarationen erzeugen keine Eigenschaften auf globalThis, 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.
  • let beginnt Deklarationen, keine Anweisungen. Das bedeutet, dass eine alleinstehende let-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

Typ
void
Beschreibung
Eine Deklarationsanweisung hat keinen 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.