Was ist der Unterschied zwischen "let" und "var"?

4541

ECMAScript 6 führte die letErklärung ein .

Ich habe gehört, dass es als "lokale" Variable beschrieben wird, bin mir aber immer noch nicht ganz sicher, wie es sich anders verhält als das varSchlüsselwort.

Was sind die Unterschiede? Wann sollte letüber verwendet werden var?

TM.
quelle
105
ECMAScript ist der Standard und letist im Entwurf der 6. Ausgabe enthalten und wird höchstwahrscheinlich in der endgültigen Spezifikation enthalten sein.
Richard Ayotte
5
Unter kangax.github.io/es5-compat-table/es6 finden Sie eine aktuelle Unterstützungsmatrix der ES6-Funktionen (einschließlich let). Zum Zeitpunkt des Schreibens unterstützen Firefox, Chrome und IE11 dies alle (obwohl ich glaube, dass die Implementierung von FF nicht ganz Standard ist).
Nico Burns
22
Die längste Zeit wusste ich nicht, dass Vars in einer for-Schleife auf die Funktion beschränkt waren, in die sie eingewickelt war. Ich erinnere mich, dass ich das zum ersten Mal herausgefunden hatte und fand es sehr dumm. Ich sehe eine gewisse Macht, obwohl ich jetzt weiß, wie die beiden aus unterschiedlichen Gründen verwendet werden könnten und wie Sie in einigen Fällen tatsächlich eine var in einer for-Schleife verwenden möchten und sie nicht auf den Block beschränken möchten.
Eric Bishard
1
Dies ist eine sehr gute Lektüre wesbos.com/javascript-scoping
onmyway133
1
Gut erklärte Antwort hier stackoverflow.com/a/43994458/5043867
Pardeep Jain

Antworten:

6101

Geltungsbereich Regeln

Der Hauptunterschied besteht in den Geltungsbereichsregeln. Variablen, die durch das varSchlüsselwort deklariert werden, werden auf den unmittelbaren Funktionskörper (daher den Funktionsumfang) beschränkt, während letVariablen auf den unmittelbaren umschließenden Block, der mit bezeichnet wird { }(daher der Blockumfang).

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar);

  {
    let baz = "Bazz";
    console.log(baz);
  }

  console.log(baz); // ReferenceError
}

run();

Der Grund, warum das letSchlüsselwort in die Sprache eingeführt wurde, war der Funktionsumfang, der verwirrend ist und eine der Hauptursachen für Fehler in JavaScript war.

Schauen Sie sich dieses Beispiel aus einer anderen Frage zum Stapelüberlauf an :

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3wurde bei jedem funcs[j]();Aufruf an die Konsole ausgegeben, da anonyme Funktionen an dieselbe Variable gebunden waren.

Die Leute mussten sofort aufgerufene Funktionen erstellen, um den korrekten Wert aus den Schleifen zu erfassen, aber das war auch haarig.

Heben

Während Variablen, die mit dem varSchlüsselwort deklariert wurden, gehisst (initialisiert mit, undefinedbevor der Code ausgeführt wird), bedeutet dies, dass sie in ihrem umschließenden Bereich bereits zugänglich sind, bevor sie deklariert werden:

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

letVariablen werden erst initialisiert, wenn ihre Definition ausgewertet ist. Der Zugriff auf sie vor der Initialisierung führt zu a ReferenceError. Die Variable soll sich vom Beginn des Blocks bis zur Verarbeitung der Initialisierung in der "zeitlichen Totzone" befinden.

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

Globale Objekteigenschaft erstellen

Auf der obersten Ebene wird letim Gegensatz dazu varkeine Eigenschaft für das globale Objekt erstellt:

var foo = "Foo";  // globally scoped
let bar = "Bar"; // globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

Neuerklärung

Im strengen Modus können varSie dieselbe Variable im selben Bereich erneut deklarieren, während letein SyntaxError ausgelöst wird.

'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
ThinkingStiff
quelle
23
Denken Sie daran, dass Sie jederzeit einen Block erstellen können. function () {code; {let inBlock = 5; } code; };
Durchschnitt Joe
177
Ist der Zweck von let-Anweisungen also nur, Speicher freizugeben, wenn er in einem bestimmten Block nicht benötigt wird?
NoBugs
219
@NoBugs, Ja, und es wird empfohlen, dass Variablen nur dort vorhanden sind, wo sie benötigt werden.
Batman
67
letBlockausdruck let (variable declaration) statementist nicht Standard und wird in Zukunft entfernt, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus
19
Ich kann mir also keinen Fall vorstellen, in dem die Verwendung von var von Nutzen ist. Könnte mir jemand ein Beispiel für eine Situation geben, in der es vorzuziehen ist, var zu verwenden?
Luis Sieira
622

letkann auch verwendet werden, um Probleme mit Verschlüssen zu vermeiden. Es bindet einen neuen Wert, anstatt eine alte Referenz beizubehalten, wie in den folgenden Beispielen gezeigt.

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

Der obige Code zeigt ein klassisches JavaScript-Schließproblem. Der Verweis auf die iVariable wird im Click-Handler-Closure gespeichert und nicht der tatsächliche Wert von i.

Jeder einzelne Klick-Handler verweist auf dasselbe Objekt, da es nur ein Zählerobjekt gibt, das 6 enthält, sodass Sie bei jedem Klick sechs erhalten.

Eine allgemeine Problemumgehung besteht darin, dies in eine anonyme Funktion zu packen und ials Argument zu übergeben. Solche Probleme können jetzt auch vermieden werden, indem letstattdessen varwie im folgenden Code gezeigt verwendet wird.

(Getestet in Chrome und Firefox 50)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

Gurpreet Singh
quelle
54
Das ist eigentlich cool. Ich würde erwarten, dass "i" außerhalb des in Klammern enthaltenen Schleifenkörpers definiert wird und KEINEN "Verschluss" um "i" bildet. Natürlich beweist Ihr Beispiel etwas anderes. Ich denke, es ist aus syntaktischer Sicht etwas verwirrend, aber dieses Szenario ist so häufig, dass es sinnvoll ist, es auf diese Weise zu unterstützen. Vielen Dank, dass Sie dies angesprochen haben.
Karol Kolenda
9
IE 11 unterstützt let, aber es warnt "6" für alle Schaltflächen. Haben Sie eine Quelle, die sagt, wie letman sich verhalten soll?
Jim Hunziker
10
Ihre Antwort scheint das richtige Verhalten zu sein: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker
11
In der Tat ist dies eine häufige Gefahr in Javascript, und jetzt kann ich sehen, warum letdies wirklich nützlich wäre. Das Festlegen von Ereignis-Listenern in einer Schleife erfordert keinen sofort aufgerufenen Funktionsausdruck mehr für das lokale Scoping ibei jeder Iteration.
Adrian Moisa
19
Die Verwendung von "let" verschiebt dieses Problem nur. Jede Iteration erstellt also einen privaten unabhängigen Blockbereich, aber die "i" -Variable kann immer noch durch nachfolgende Änderungen innerhalb des Blocks beschädigt werden (vorausgesetzt, die Iteratorvariable wird normalerweise nicht innerhalb des Blocks geändert, aber andere deklarierte let-Variablen innerhalb des Blocks können durchaus sein) , und jede Funktion innerhalb des Blocks deklariert, wenn sie aufgerufen wird , beschädigt der Wert von „i“ für andere Funktionen deklariert innerhalb des Blocks , weil sie nicht den gleichen privaten Block Umfang Aktie daher der gleiche Verweis auf „i“.
Gary
199

Was ist der Unterschied zwischen letund var?

  • Eine mit einer varAnweisung definierte Variable ist in der gesamten Funktion, in der sie definiert ist, vom Beginn der Funktion an bekannt. (*)
  • Eine mit einer letAnweisung definierte Variable ist ab dem Zeitpunkt ihrer Definition nur in dem Block bekannt, in dem sie definiert ist. (**)

Beachten Sie den folgenden Code, um den Unterschied zu verstehen:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Hier können wir sehen, dass unsere Variable jnur in der ersten for-Schleife bekannt ist, nicht jedoch vorher und nachher. Unsere Variable iist jedoch in der gesamten Funktion bekannt.

Beachten Sie auch, dass Variablen mit Blockbereich nicht bekannt sind, bevor sie deklariert werden, da sie nicht angehoben werden. Sie dürfen auch nicht dieselbe Variable mit Blockbereich innerhalb desselben Blocks neu deklarieren. Dies macht Variablen mit Blockbereich weniger fehleranfällig als Variablen mit globalem oder funktionalem Bereich, die angehoben werden und bei mehreren Deklarationen keine Fehler verursachen.


Ist es heute sicher zu benutzen let?

Einige Leute würden argumentieren, dass wir in Zukunft NUR let-Anweisungen verwenden werden und dass var-Anweisungen veraltet sein werden. Der JavaScript-Guru Kyle Simpson hat einen sehr ausführlichen Artikel darüber geschrieben, warum er glaubt, dass dies nicht der Fall sein wird .

Heute ist dies jedoch definitiv nicht der Fall. Tatsächlich müssen wir uns fragen, ob es sicher ist, die letAussage zu verwenden. Die Antwort auf diese Frage hängt von Ihrer Umgebung ab:

  • Wenn Sie serverseitigen JavaScript-Code ( Node.js ) schreiben , können Sie die letAnweisung sicher verwenden .

  • Wenn Sie clientseitigen JavaScript-Code schreiben und einen browserbasierten Transpiler (wie Traceur oder babel-standalone ) verwenden, können Sie die letAnweisung sicher verwenden. Ihr Code ist jedoch in Bezug auf die Leistung wahrscheinlich alles andere als optimal.

  • Wenn Sie clientseitigen JavaScript-Code schreiben und einen knotenbasierten Transpiler verwenden (wie das Traceur-Shell-Skript oder Babel ), können Sie die letAnweisung sicher verwenden . Und da Ihr Browser nur über den transpilierten Code Bescheid weiß, sollten die Leistungsnachteile begrenzt sein.

  • Wenn Sie clientseitigen JavaScript-Code schreiben und keinen Transpiler verwenden, müssen Sie die Browserunterstützung in Betracht ziehen.

    Es gibt noch einige Browser, die überhaupt nicht unterstützen let:

Geben Sie hier die Bildbeschreibung ein


So behalten Sie den Überblick über die Browserunterstützung

Auf dieser Seite finden Sie eine aktuelle Übersicht darüber, welche Browser die letAussage zum Zeitpunkt des Lesens dieser Antwort unterstützen .Can I Use


(*) Global und funktional scoped Variablen initialisiert und verwendet werden , bevor sie deklariert werden , da JavaScript - Variablen werden gehisst . Dies bedeutet, dass Deklarationen immer ganz oben im Geltungsbereich stehen.

(**) Variablen mit Blockbereich werden nicht angehoben

John Slegers
quelle
14
zur Antwort v4: iIst überall im Funktionsblock bekannt! Es beginnt als undefined(aufgrund des Hebens), bis Sie einen Wert zuweisen! ps: letwird ebenfalls hochgezogen (an die Spitze des Blocks), gibt jedoch ein Zeichen, ReferenceErrorwenn im Block vor der ersten Zuweisung darauf verwiesen wird. (ps2: Ich bin ein Pro-Semikolon-Typ, aber nach einem Block brauchst du wirklich kein Semikolon). Trotzdem danke, dass Sie den Reality-Check bezüglich Support hinzugefügt haben!
GitaarLAB
@GitaarLAB: Laut Mozilla Developer Network : "In ECMAScript 2015 unterliegen Let-Bindungen keinem Variablen-Hoisting, was bedeutet, dass Let-Deklarationen nicht an die Spitze des aktuellen Ausführungskontexts verschoben werden." - Wie auch immer, ich habe einige Verbesserungen an meiner Antwort vorgenommen, die den Unterschied im Hubverhalten zwischen letund verdeutlichen sollen var!
John Slegers
1
Ihre Antwort hat sich sehr verbessert (ich habe sie gründlich überprüft). Beachten Sie, dass derselbe Link, auf den Sie in Ihrem Kommentar verwiesen haben, auch lautet: "Die (let) -Variable befindet sich vom Beginn des Blocks bis zur Verarbeitung der Initialisierung in einer" zeitlichen Totzone " ." Das bedeutet, dass der 'Bezeichner' (die Textzeichenfolge 'reserviert', um auf 'etwas' zu verweisen) bereits im relevanten Bereich reserviert ist, andernfalls würde er Teil des Bereichs root / host / window werden. Für mich persönlich bedeutet "Heben" nichts anderes als das Reservieren / Verknüpfen deklarierter "Identifikatoren" mit ihrem relevanten Umfang; ohne deren Initialisierung / Zuweisung / Modifizierbarkeit!
GitaarLAB
Und .. + 1. Der Artikel von Kyle Simpson, den Sie verlinkt haben, ist eine ausgezeichnete Lektüre. Vielen Dank dafür! Es ist auch klar über die "zeitliche Totzone" alias "TDZ". Eine interessante Sache, die ich hinzufügen möchte: Ich habe das auf MDN gelesen letund constwurde empfohlen, es nur zu verwenden, wenn Sie tatsächlich ihre zusätzlichen Funktionen benötigen , da das Erzwingen / Überprüfen dieser zusätzlichen Funktionen (wie z. B. Nur-Schreiben-Konstante) zu mehr Arbeit führt '(und zusätzliche Scope-Knoten im Scope-Baum) für die (aktuelle) Engine (s) zum Erzwingen / Überprüfen / Überprüfen / Einrichten.
GitaarLAB
1
Beachten Sie, dass MDN sagt, dass IE Let korrekt interpretiert. Welches ist es? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka Hesselink
146

Hier ist eine Erklärung des letSchlüsselworts mit einigen Beispielen.

letfunktioniert sehr ähnlich var. Der Hauptunterschied besteht darin, dass der Umfang einer varVariablen die gesamte einschließende Funktion ist

Diese Tabelle auf Wikipedia zeigt, welche Browser Javascript 1.7 unterstützen.

Beachten Sie, dass dies nur von Mozilla- und Chrome-Browsern unterstützt wird. IE, Safari und möglicherweise andere nicht.

Ben S.
quelle
5
Das Schlüsselstück des Textes aus dem verknüpften Dokument scheint zu sein: "Lassen Sie uns sehr ähnlich wie var funktionieren. Der Hauptunterschied besteht darin, dass der Umfang einer var-Variablen die gesamte einschließende Funktion ist."
Michael Burr
50
Obwohl es technisch korrekt ist zu sagen, dass IE es nicht unterstützt, ist es korrekter zu sagen, dass es sich nur um eine Mozilla-Erweiterung handelt.
olliej
55
@olliej, eigentlich ist Mozilla dem Spiel einfach voraus. Siehe Seite 19 von ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton
@ TylerCrompton, das sind nur die Wörter, die seit Jahren reserviert sind. Als Mozilla hinzugefügt wurde, war es eine reine Mozilla-Erweiterung ohne verwandte Spezifikation. ES6 sollte das Verhalten für let-Anweisungen definieren, aber das kam, nachdem Mozilla die Syntax eingeführt hatte. Denken Sie daran, Moz hat auch E4X, das völlig tot und nur Moz ist.
olliej
9
IE11 fügte Unterstützung für let msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
eloyesp
112

Der akzeptierten Antwort fehlt ein Punkt:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Lcf.vs
quelle
19
Die akzeptierte Antwort erklärt diesen Punkt in ihrem Beispiel NICHT. Die akzeptierte Antwort demonstrierte dies nur in einem forSchleifeninitialisierer, was den Anwendungsbereich der Einschränkungen von dramatisch einschränkte let. Upvoted.
Jon Davis
37
@ stimulpy77 Es wird explizit angegeben, dass "let auf den nächsten umschließenden Block beschränkt ist"; Muss jede Art und Weise, die sich manifestiert, einbezogen werden?
Dave Newton
6
Es gab viele Beispiele und keines von ihnen hat die Angelegenheit richtig demonstriert. Ich hätte vielleicht sowohl die akzeptierte als auch diese Antwort positiv bewertet?
Jon Davis
5
Dieser Beitrag zeigt, dass ein "Block" einfach eine Reihe von Zeilen sein kann, die in Klammern eingeschlossen sind. dh es muss nicht mit irgendeiner Art von Kontrollfluss, Schleife usw. verbunden sein
webelo
81

let

Bereich blockieren

Mit dem letSchlüsselwort deklarierte Variablen haben einen Blockumfang. Dies bedeutet, dass sie nur in dem Block verfügbar sind , in dem sie deklariert wurden.

Auf der obersten Ebene (außerhalb einer Funktion)

Auf der obersten Ebene leterstellen mit deklarierte Variablen keine Eigenschaften für das globale Objekt.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

Innerhalb einer Funktion

Innerhalb einer Funktion (aber außerhalb eines Blocks) lethat der gleiche Umfang wie var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

In einem Block

Auf Variablen, die letinnerhalb eines Blocks deklariert wurden, kann außerhalb dieses Blocks nicht zugegriffen werden.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

In einer Schleife

Mit letin Schleifen deklarierte Variablen können nur innerhalb dieser Schleife referenziert werden.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Schleifen mit Verschlüssen

Wenn Sie letanstelle vareiner Schleife verwenden, erhalten Sie mit jeder Iteration eine neue Variable. Das bedeutet, dass Sie einen Verschluss sicher in einer Schleife verwenden können.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

Zeitliche Totzone

Aufgrund der zeitlichen Totzone kann auf Variablen, die mit deklariert wurden, letnicht zugegriffen werden, bevor sie deklariert wurden. Der Versuch, dies zu tun, löst einen Fehler aus.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

Keine erneute Erklärung

Sie können dieselbe Variable nicht mehrmals mit deklarieren let. Sie können eine Variable auch nicht letmit demselben Bezeichner deklarieren wie eine andere Variable, die mit deklariert wurde var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

constist ziemlich ähnlich zu let- es hat einen Blockumfang und hat TDZ. Es gibt jedoch zwei Dinge, die unterschiedlich sind.

Keine Neuzuweisung

Mit deklarierte Variable constkann nicht neu zugewiesen werden.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

Beachten Sie, dass dies nicht bedeutet, dass der Wert unveränderlich ist. Seine Eigenschaften können noch geändert werden.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

Wenn Sie ein unveränderliches Objekt haben möchten, sollten Sie verwenden Object.freeze().

Initializer ist erforderlich

Sie müssen immer einen Wert angeben, wenn Sie eine Variable mit deklarieren const.

const a; // SyntaxError: Missing initializer in const declaration
Michał Perłakowski
quelle
51

Hier ist ein Beispiel für den Unterschied zwischen den beiden (Unterstützung für Chrom wurde gerade gestartet):
Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen, hat die var jVariable immer noch einen Wert außerhalb des for-Schleifenbereichs (Block Scope), aber die let iVariable ist außerhalb des for-Schleifenbereichs undefiniert.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);

vlio20
quelle
2
Welches Werkzeug schaue ich hier an?
Barton
20
Chrome devtools
vlio20
Als Entwickler von Desktop-Applets für Cinnamon war ich solchen glänzenden Tools nicht ausgesetzt.
Barton
48

Es gibt einige subtile Unterschiede - das letScoping verhält sich eher wie das variable Scoping in mehr oder weniger anderen Sprachen.

zB Es erstreckt sich auf den umschließenden Block. Sie existieren nicht, bevor sie deklariert wurden usw.

Es ist jedoch erwähnenswert, dass dies letnur ein Teil neuerer Javascript-Implementierungen ist und unterschiedliche Grade an Browserunterstützung bietet .

olliej
quelle
11
Es ist auch erwähnenswert, dass ECMAScript der Standard ist und letim Entwurf der 6. Ausgabe enthalten ist und höchstwahrscheinlich in der endgültigen Spezifikation enthalten sein wird.
Richard Ayotte
23
Das ist der Unterschied, den 3 Jahre machen: D
olliej
4
Gerade über diese Frage gestillt und im Jahr 2012 ist es immer noch so, dass nur Mozilla-Browser unterstützen let. Safari, IE und Chome tun dies nicht.
Pseudosavant
2
Die Idee, versehentlich einen Teilblockbereich bei einem Unfall zu erstellen, ist ein guter Punkt. Achten Sie darauf, letdass Sie keine Variable verwenden, die durch eine letam oberen Rand Ihres Blocks definierte Variable definiert ist . Wenn Sie eine ifAnweisung haben, die mehr als nur ein paar Codezeilen umfasst, können Sie vergessen, dass Sie diese Variable erst verwenden können, nachdem sie definiert wurde. Toller Punkt !!!
Eric Bishard
2
@EricB: Ja und Nein: "In ECMAScript 2015 let wird die Variable an den Anfang des Blocks gehoben. Wenn Sie jedoch auf die Variable im Block vor der Variablendeklaration verweisen, wird ein ReferenceError angezeigt (mein Hinweis: anstelle von good old undefined) Die Variable befindet sich vom Beginn des Blocks bis zur Verarbeitung der Deklaration in einer 'zeitlichen Totzone'. " Gleiches gilt für "switch-Anweisungen, da nur ein Block zugrunde liegt". Quelle: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB
27

Der Hauptunterschied ist der Bereichsunterschied , während let nur innerhalb des deklarierten Bereichs verfügbar sein kann , wie z. B. in for-Schleife. Auf var kann beispielsweise außerhalb der Schleife zugegriffen werden. Aus der Dokumentation in MDN (Beispiele auch aus MDN):

Mit let können Sie Variablen deklarieren, deren Umfang auf den Block, die Anweisung oder den Ausdruck beschränkt ist, für den sie verwendet werden. Dies unterscheidet sich vom Schlüsselwort var , das eine Variable global oder lokal für eine gesamte Funktion unabhängig vom Blockbereich definiert.

Von let deklarierte Variablen haben als Gültigkeitsbereich den Block, in dem sie definiert sind, sowie alle enthaltenen Unterblöcke. Auf diese Weise funktioniert let sehr ähnlich wie var . Der Hauptunterschied besteht darin, dass der Gültigkeitsbereich einer var- Variablen die gesamte einschließende Funktion ist:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

Lassen Sie auf der obersten Ebene von Programmen und Funktionen im Gegensatz zu var keine Eigenschaft für das globale Objekt erstellen. Zum Beispiel:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

Wenn Sie innerhalb eines Blocks verwendet werden, beschränken Sie den Gültigkeitsbereich der Variablen auf diesen Block. Beachten Sie den Unterschied zwischen var, dessen Gültigkeitsbereich innerhalb der Funktion liegt, in der er deklariert ist.

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

Vergessen Sie auch nicht, dass es sich um eine ECMA6-Funktion handelt, die noch nicht vollständig unterstützt wird. Daher ist es besser, sie immer mit Babel usw. auf ECMA5 zu übertragen, um weitere Informationen zum Besuch der Babel-Website zu erhalten

Alireza
quelle
24
  • Variable nicht heben

    letwird nicht auf den gesamten Umfang des Blocks angehoben, in dem sie erscheinen. Im Gegensatz dazu varkönnte wie folgt angehoben werden.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }

    Eigentlich Per @Bergi, Beide varund letwerden gehisst .

  • Müllabfuhr

    Der Blockumfang von letist nützlich für Verschlüsse und Speicherbereinigung, um Speicher zurückzugewinnen. Erwägen,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });

    Der clickHandler-Rückruf benötigt die hugeDataVariable überhaupt nicht. Theoretisch könnte process(..)die riesige Datenstruktur nach Läufen hugeDatadurch Müll gesammelt werden. Es ist jedoch möglich, dass einige JS-Engines diese riesige Struktur beibehalten müssen, da die clickFunktion über den gesamten Bereich geschlossen ist.

    Der Blockumfang kann jedoch dazu führen, dass diese riesige Datenstruktur zum gesammelten Müll wird.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
  • let Schleifen

    letin der Schleife kann es erneut an jede Iteration der Schleife binden , wobei sichergestellt wird, dass der Wert vom Ende der vorherigen Schleifeniteration neu zugewiesen wird. Erwägen,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    Ersetzen Sie jedoch vardurchlet

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }

    Da Sie leteine neue lexikalische Umgebung mit diesen Namen für a) den Initialisiererausdruck b) jede Iteration (vor der Auswertung des Inkrementausdrucks) erstellen, finden Sie hier weitere Details .

zangw
quelle
4
Ja, sie werden gehisst, verhalten sich aber so, als ob sie wegen der zeitlichen Totzone (Trommelwirbel) nicht gehisst werden - ein sehr dramatischer Name für eine Kennung, auf die erst zugegriffen werden kann, wenn sie deklariert wird :-)
Drenai,
Also lassen Sie uns gehisst, aber nicht verfügbar? Wie unterscheidet sich das von "nicht gehisst"?
N-ate
Hoffentlich kommen Brian oder Bergi zurück, um dies zu beantworten. Wird die Vermietungserklärung gehisst, nicht aber die Abtretung? Vielen Dank!
N-ate
1
@ N-ate, Hier ist ein Beitrag von Bergi, vielleicht findest du darin eine Antwort.
Zangw
Es ist interessant, dass es sogar als Heben bezeichnet wird, wenn es um das Vermieten geht. Ich verstehe, dass die Parsing-Engine es technisch vorab erfasst, aber in jeder Hinsicht sollte ein Programmierer es so behandeln, als ob es nicht existiert. Das Heben von var hat dagegen Auswirkungen auf einen Programmierer.
N-ate
19

Hier ist ein Beispiel, um das zu ergänzen, was andere bereits geschrieben haben. Angenommen, Sie möchten ein Array von Funktionen erstellen adderFunctions, wobei jede Funktion ein einzelnes Number-Argument verwendet und die Summe des Arguments und des Funktionsindex im Array zurückgibt. Der Versuch, adderFunctionsmit einer Schleife mithilfe des varSchlüsselworts zu generieren, funktioniert nicht so, wie es jemand naiv erwartet:

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

Der obige Prozess generiert nicht das gewünschte Funktionsarray, da ider Gültigkeitsbereich über die Iteration des forBlocks hinausgeht , in dem jede Funktion erstellt wurde. Stattdessen ibezieht sich der Abschluss in jeder Funktion iam Ende der Schleife auf den Wert am Ende der Schleife (1000) für jede anonyme Funktion in adderFunctions. Das wollten wir überhaupt nicht: Wir haben jetzt ein Array von 1000 verschiedenen Funktionen im Speicher mit genau dem gleichen Verhalten. Und wenn wir anschließend den Wert von aktualisieren i, wirkt sich die Mutation auf alle aus adderFunctions.

Wir können es jedoch erneut mit dem letSchlüsselwort versuchen :

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

Dieses Mal iwird bei jeder Iteration der forSchleife zurückgebunden. Jede Funktion behält jetzt den Wert von izum Zeitpunkt der Erstellung der Funktion bei und adderFunctionsverhält sich wie erwartet.

Wenn Sie nun die beiden Verhaltensweisen mischen, werden Sie wahrscheinlich sehen, warum es nicht empfohlen wird, die neueren letund constdie älteren varim selben Skript zu mischen . Dies kann zu einem spektakulär verwirrenden Code führen.

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

Lass dir das nicht passieren. Verwenden Sie einen Linter.

HINWEIS: Dies ist ein Lehrbeispiel, das das var/ letVerhalten in Schleifen und mit Funktionsabschlüssen demonstrieren soll , die ebenfalls leicht zu verstehen wären. Dies wäre eine schreckliche Möglichkeit, Zahlen hinzuzufügen. Die allgemeine Technik zum Erfassen von Daten in anonymen Funktionsabschlüssen kann jedoch in der realen Welt in anderen Kontexten auftreten. YMMV.

abroz
quelle
2
@aborz: Auch sehr coole anonyme Funktionssyntax im zweiten Beispiel. Es ist genau das, was ich in C # gewohnt bin. Ich habe heute etwas gelernt.
Barton
Korrektur: Technisch gesehen ist die hier beschriebene Pfeilfunktionssyntax => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton
3
Eigentlich brauchst du nicht let value = i;. Die forAnweisung erstellt einen lexikalischen Block.
Zahnbürste
17

Der Unterschied liegt im Umfang der mit jedem deklarierten Variablen.

In der Praxis gibt es eine Reihe nützlicher Konsequenzen des unterschiedlichen Umfangs:

  1. letVariablen sind nur im nächsten umschließenden Block ( { ... }) sichtbar .
  2. letVariablen können nur in Codezeilen verwendet werden, die nach der Deklaration der Variablen auftreten (obwohl sie angehoben werden !).
  3. letVariablen dürfen nicht durch ein nachfolgendes varoder neu deklariert werden let.
  4. Globale letVariablen werden dem globalen windowObjekt nicht hinzugefügt .
  5. letVariablen sind bei Schließungen einfach zu verwenden (sie verursachen keine Rennbedingungen ).

Die durch letdie Einschränkung der Sichtbarkeit der Variablen auferlegten Einschränkungen erhöhen die Wahrscheinlichkeit, dass unerwartete Namenskollisionen frühzeitig erkannt werden. Dies erleichtert das Verfolgen und Überlegen von Variablen, einschließlich ihrer Erreichbarkeit (was bei der Rückgewinnung nicht verwendeten Speichers hilft).

Folglich ist letes weniger wahrscheinlich, dass Variablen Probleme verursachen, wenn sie in großen Programmen verwendet werden oder wenn unabhängig entwickelte Frameworks auf neue und unerwartete Weise kombiniert werden.

varDies kann dennoch nützlich sein, wenn Sie sicher sind, dass Sie den Einzelbindungseffekt wünschen, wenn Sie einen Abschluss in einer Schleife verwenden (Nr. 5) oder wenn Sie extern sichtbare globale Variablen in Ihrem Code deklarieren (Nr. 4). Die Verwendung varfür den Export kann ersetzt werden, wenn exportder Transpiler-Speicherplatz in die Kernsprache migriert wird.

Beispiele

1. Keine Verwendung außerhalb des nächstgelegenen umschließenden Blocks: Dieser Codeblock gibt einen Referenzfehler aus, da die zweite Verwendung xaußerhalb des Blocks erfolgt, in dem er deklariert ist mit let:

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

Im Gegensatz dazu varfunktioniert das gleiche Beispiel mit .

2. Keine Verwendung vor der Deklaration:
Dieser Codeblock löst ein aus, ReferenceErrorbevor der Code ausgeführt werden kann, da er verwendet xwird, bevor er deklariert wird:

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

Im Gegensatz dazu varanalysiert und läuft das gleiche Beispiel ohne Ausnahmen.

3. Keine erneute Deklaration: Der folgende Code zeigt, dass eine mit deklarierte Variable letmöglicherweise später nicht erneut deklariert wird:

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. Globals, die nicht an Folgendes gebunden sind window:

var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link);  // OK
console.log(window.link);  // undefined (GOOD!)
console.log(window.button);  // OK

5. Einfache Verwendung mit Verschlüssen: Mit deklarierte Variablen varfunktionieren nicht gut mit Verschlüssen in Schleifen. Hier ist eine einfache Schleife, die die Folge von Werten ausgibt, die die Variable izu verschiedenen Zeitpunkten hat:

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

Im Einzelnen gibt dies Folgendes aus:

i is 0
i is 1
i is 2
i is 3
i is 4

In JavaScript verwenden wir Variablen häufig zu einem wesentlich späteren Zeitpunkt als beim Erstellen. Wenn wir dies demonstrieren, indem wir die Ausgabe mit einem an Folgendes übergebenen Abschluss verzögern setTimeout:

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... die Ausgabe bleibt unverändert, solange wir dabei bleiben let. Im Gegensatz dazu, wenn wir var istattdessen verwendet hätten:

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... die Schleife gibt unerwartet fünfmal "i is 5" aus:

i is 5
i is 5
i is 5
i is 5
i is 5
Mormegil
quelle
5
# 5 wird nicht durch eine Rennbedingung verursacht. Wenn Sie varanstelle von verwenden let, entspricht der Code: var i = 0; while (i < 5) { doSomethingLater(); i++; } iBefindet sich außerhalb des Abschlusses und zum Zeitpunkt der doSomethingLater()Ausführungi bereits fünfmal inkrementiert, die Ausgabe i is 5fünfmal erfolgt. Bei Verwendung letbefindet sich die Variable iinnerhalb des Abschlusses, sodass jeder asynchrone Aufruf eine eigene Kopie erhält, ianstatt die 'globale' zu verwenden, mit der erstellt wurde var.
Daniel T.
@ DanielT.: Ich glaube nicht, dass die Transformation des Heraushebens der Variablendefinition aus dem Schleifeninitialisierer etwas erklärt. Das ist einfach die normale Definition der Semantik von for. Eine genauere Transformation ist zwar komplizierter, aber das klassische for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i ist $ {j}, ), 125/*ms*/); })(i); }das einen "Funktionsaktivierungsdatensatz" einführt, um jeden Wert von imit dem Namen jinnerhalb der Funktion zu speichern .
Mormegil
14

Mögen die folgenden zwei Funktionen den Unterschied zeigen:

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}
Abdennour TOUMI
quelle
13

let ist interessant, weil es uns erlaubt, so etwas zu tun:

(() => {
    var count = 0;

    for (let i = 0; i < 2; ++i) {
        for (let i = 0; i < 2; ++i) {
            for (let i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Was zur Zählung führt [0, 7].

Wohingegen

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Zählt nur [0, 1].

Dmitry
quelle
2
Dies ist das erste Mal, dass ich jemanden gesehen habe, der sich so verhält, als wäre eine variable Abschattung wünschenswert. Nein, der Zweck von let ist nicht, Schatten zu aktivieren
John Haugeland
1
Zweck? Es ist ein Konstrukt, Sie können es verwenden, wie Sie möchten. Eine der interessanten Möglichkeiten ist folgende.
Dmitry
13

Funktion VS Blockumfang:

Der wesentliche Unterschied zwischen varund letist , dass die deklarierten Variablen mit varist Funktion scoped . Während Funktionen erklärt mit letsind Block scoped . Zum Beispiel:

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

Variablen mit var:

Wenn die erste Funktion testVaraufgerufen wird, ist die mit deklarierte Variable foo varaußerhalb der ifAnweisung weiterhin verfügbar . Diese Variable foowäre im Rahmen der Funktion überall verfügbar .testVar

Variablen mit let:

Wenn die zweite Funktion testLetaufgerufen wird, ist die mit deklarierte Variablenleiste letnur innerhalb der ifAnweisung zugänglich . Da mit Variablen deklariert letwird Block scoped (wobei ein Block ist der Code zwischen geschweiften Klammern z if{}, for{}, function{}).

let Variablen werden nicht gehisst:

Ein weiterer Unterschied zwischen varund letbesteht darin, dass Variablen mit deklariert mit let nicht angehoben werden . Ein Beispiel ist der beste Weg, um dieses Verhalten zu veranschaulichen:

Variablen mit werden let nicht gehisst:

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

Variablen mit var do get hochgezogen:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

Global lethängt nicht daranwindow :

Eine letim globalen Bereich mit deklarierte Variable (dies ist Code, der nicht in einer Funktion enthalten ist) wird nicht als Eigenschaft für das globale windowObjekt hinzugefügt . Zum Beispiel (dieser Code befindet sich im globalen Bereich):

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


Wann sollte letüber verwendet werden var?

Verwenden letSie es, varwann immer Sie können, da es einfach spezifischer ist. Dies reduziert mögliche Namenskonflikte, die beim Umgang mit einer großen Anzahl von Variablen auftreten können. varkann verwendet werden, wenn eine globale Variable explizit im windowObjekt enthalten sein soll (immer sorgfältig prüfen, ob dies wirklich erforderlich ist).

Willem van der Veen
quelle
9

Es scheint auch, dass "var" zumindest in Visual Studio 2015, TypeScript 1.5, mehrere Deklarationen desselben Variablennamens in einem Block zulässt und "let" nicht.

Dies erzeugt keinen Kompilierungsfehler:

var x = 1;
var x = 2;

Dieser Wille:

let x = 1;
let x = 2;
RDoc
quelle
9

var ist eine Variable für den globalen Bereich (anhebbar).

letund constist Blockumfang.

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined

Moslemischer Shahsavan
quelle
8

Beim Benutzen let

Das letSchlüsselwort hängt die Variablendeklaration an den Gültigkeitsbereich des Blocks (üblicherweise eines { .. }Paares) an, in dem es enthalten ist. Mit anderen Worten, es letübernimmt implizit den Gültigkeitsbereich eines Blocks für seine Variablendeklaration.

letAuf Variablen kann im windowObjekt nicht zugegriffen werden, da auf sie nicht global zugegriffen werden kann.

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

Beim Benutzen var

var und Variablen in ES5 haben Bereiche in Funktionen, was bedeutet, dass die Variablen innerhalb der Funktion und nicht außerhalb der Funktion selbst gültig sind.

varAuf Variablen kann im windowObjekt zugegriffen werden, da auf sie nicht global zugegriffen werden kann.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

Wenn Sie mehr wissen möchten, lesen Sie weiter unten

Eine der bekanntesten Interviewfragen zum Umfang kann auch die genaue Verwendung von letund varwie folgt genügen .

Beim Benutzen let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

Dies liegt daran, wenn bei der Verwendung let für jede Schleifeniteration die Variable einen Gültigkeitsbereich hat und eine eigene Kopie hat.

Beim Benutzen var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

Dies liegt daran, dass bei Verwendung varfür jede Schleifeniteration die Variable einen Gültigkeitsbereich hat und eine gemeinsam genutzte Kopie hat.

Ankur Soni
quelle
8

In den meisten grundlegenden Begriffen,

for (let i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i accessible ✔️

⚡️ Sandbox zum Herumspielen ↓

Edit let vs var

Hasan Sefa Ozalp
quelle
7

Wenn ich die Spezifikationen richtig lese, kann ich let dankenswerterweise auch nutzen, um selbstaufrufende Funktionen zu vermeiden , mit denen nur private Mitglieder simuliert werden - ein beliebtes Entwurfsmuster, das die Lesbarkeit des Codes verringert, das Debuggen erschwert, keinen echten Codeschutz oder andere Vorteile bietet - außer möglicherweise die Zufriedenheit anderer Wunsch nach Semantik, also hör auf, sie zu benutzen. /schimpfen

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Siehe ' Emulieren privater Schnittstellen '

Daniel Sokolowski
quelle
Können Sie näher erläutern, wie sofort aufgerufene Funktionsausdrücke keinen „Codeschutz“ bieten und letdies auch tun ? (Ich nehme an, Sie meinen IIFE mit "selbstaufrufender Funktion".)
Robert Siemer
Und warum setzen Sie hiddenPropertyim Konstruktor? Es gibt nur eine hiddenPropertyfür alle Instanzen in Ihrer „Klasse“.
Robert Siemer
4

Einige Hacks mit let:

1.

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2.

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

3.

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

Getter und Setter mit let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)
zloctb
quelle
bitte was tun , um diesen Mittelwert let { type, name, value } = node;? Sie erstellen ein neues Objekt mit 3 Eigenschaften Typ / Name / Wert und initialisieren diese mit den Eigenschaftenwerten vom Knoten?
AlainIb
In Beispiel 3 deklarieren Sie den Knoten erneut, der eine Ausnahme verursacht. Diese Beispiele funktionieren auch perfekt var.
Rehan Haider
4

let vs var. Es geht nur um Umfang .

var-Variablen sind global und können grundsätzlich überall aufgerufen werden, während let-Variablen nicht global sind und nur existieren, bis eine schließende Klammer sie beendet.

Sehen Sie sich mein Beispiel unten an und beachten Sie, wie sich die Variable lion (let) in den beiden console.logs unterschiedlich verhält. In der 2. console.log wird der Gültigkeitsbereich überschritten.

var cat = "cat";
let dog = "dog";

var animals = () => {
    var giraffe = "giraffe";
    let lion = "lion";

    console.log(cat);  //will print 'cat'.
    console.log(dog);  //will print 'dog', because dog was declared outside this function (like var cat).

    console.log(giraffe); //will print 'giraffe'.
    console.log(lion); //will print 'lion', as lion is within scope.
}

console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
daCoda
quelle
4

ES6 führte zwei neue Schlüsselwörter ( let und const ) ein, die sich mit var abwechseln .

Wenn Sie eine Verzögerung auf Blockebene benötigen, können Sie let und const anstelle von var verwenden.

Die folgende Tabelle fasst den Unterschied zwischen var, let und const zusammen

Geben Sie hier die Bildbeschreibung ein

Srikrushna
quelle
3

let ist ein Teil von es6. Diese Funktionen erklären den Unterschied auf einfache Weise.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
Vipul Jain
quelle
3

Das Folgende zeigt, wie sich 'let' und 'var' im Umfang unterscheiden:

let gfoo = 123;
if (true) {
    let gfoo = 456;
}
console.log(gfoo); // 123

var hfoo = 123;
if (true) {
    var hfoo = 456;
}
console.log(hfoo); // 456

Die gfoo, definiert durch letzunächst im globalen Bereich , und wenn wir erklären , gfooin der wieder if clauseseinen Umfang geändert und wenn ein neuer Wert auf die Variable in diesem Bereich zugewiesen wird es keinen Einfluss auf die globale Reichweite.

Während hfoodefiniert durch varzunächst im globalen Bereich liegt , aber wenn wir es innerhalb des deklarieren if clause, berücksichtigt es den globalen Bereich hfoo, obwohl var erneut verwendet wurde, um es zu deklarieren. Und wenn wir seinen Wert neu zuweisen, sehen wir, dass auch der globale Bereich hfoo betroffen ist. Dies ist der Hauptunterschied.

Piklu Dey
quelle
2

Wie oben erwähnt:

Der Unterschied liegt im Umfang. varist auf den nächsten Funktionsblock und letauf den nächsten umschließenden Block beschränkt , der kleiner als ein Funktionsblock sein kann. Beide sind global, wenn sie sich außerhalb eines Blocks befinden. Sehen wir uns ein Beispiel an:

Beispiel 1:

In meinen beiden Beispielen habe ich eine Funktion myfunc. myfuncenthält eine Variable myvargleich 10. In meinem ersten Beispiel überprüfe ich, ob myvargleich 10 ( myvar==10) ist. Wenn ja, deklariere ich eine Variable myvar(jetzt habe ich zwei myvar-Variablen) mit dem varSchlüsselwort und weise ihr einen neuen Wert zu (20). In der nächsten Zeile drucke ich den Wert auf meiner Konsole. Nach dem bedingten Block drucke ich wieder den Wert von myvarauf meiner Konsole. Wenn Sie sich die Ausgabe von ansehen myfunc, myvarhat der Wert 20.

Schlüsselwort lassen

Beispiel 2: In meinem zweiten Beispiel vardeklariere ich anstelle des Schlüsselworts in meinem bedingten Block die myvarVerwendung des letSchlüsselworts. Wenn ich jetzt anrufe, myfunc bekomme ich zwei verschiedene Ausgänge: myvar=20und myvar=10.

Der Unterschied ist also sehr einfach, dh sein Umfang.

N Randhawa
quelle
3
Bitte posten Sie keine Bilder von Code, dies wird als schlechte Praxis auf SO angesehen, da es für zukünftige Benutzer nicht durchsuchbar ist (sowie Bedenken hinsichtlich der Barrierefreiheit). Diese Antwort fügt auch nichts hinzu, was andere Antworten noch nicht angesprochen haben.
Inostia
2

Ich möchte diese Schlüsselwörter mit dem Ausführungskontext verknüpfen, da der Ausführungskontext dabei wichtig ist. Der Ausführungskontext besteht aus zwei Phasen: einer Erstellungsphase und einer Ausführungsphase. Darüber hinaus verfügt jeder Ausführungskontext über eine variable Umgebung und eine äußere Umgebung (seine lexikalische Umgebung).

Während der Erstellungsphase eines Ausführungskontexts speichern var, let und const ihre Variable weiterhin im Speicher mit einem undefinierten Wert in der Variablenumgebung des angegebenen Ausführungskontexts. Der Unterschied liegt in der Ausführungsphase. Wenn Sie eine mit var definierte Variable referenzieren, bevor ihr ein Wert zugewiesen wird, ist sie nur undefiniert. Es wird keine Ausnahme gemacht.

Sie können jedoch nicht auf die mit let oder const deklarierte Variable verweisen, bis sie deklariert ist. Wenn Sie versuchen, es zu verwenden, bevor es deklariert wird, wird während der Ausführungsphase des Ausführungskontexts eine Ausnahme ausgelöst. Jetzt befindet sich die Variable dank der Erstellungsphase des Ausführungskontexts weiterhin im Speicher, aber die Engine erlaubt Ihnen nicht, sie zu verwenden:

function a(){
    b;
    let b;
}
a();
> Uncaught ReferenceError: b is not defined

Wenn bei einer mit var definierten Variablen die Engine die Variable in der Variablenumgebung des aktuellen Ausführungskontexts nicht finden kann, geht sie die Bereichskette (die äußere Umgebung) hoch und überprüft die Variablenumgebung der äußeren Umgebung auf die Variable. Wenn es dort nicht gefunden werden kann, wird die Scope-Kette weiter durchsucht. Dies ist bei let und const nicht der Fall.

Das zweite Merkmal von let ist die Einführung des Blockbereichs. Blöcke werden durch geschweifte Klammern definiert. Beispiele sind Funktionsblöcke, wenn Blöcke, für Blöcke usw. Wenn Sie eine Variable mit let innerhalb eines Blocks deklarieren, ist die Variable nur innerhalb des Blocks verfügbar. Tatsächlich wird jedes Mal, wenn der Block ausgeführt wird, z. B. innerhalb einer for-Schleife, eine neue Variable im Speicher erstellt.

ES6 führt auch das Schlüsselwort const zum Deklarieren von Variablen ein. const hat auch einen Blockumfang. Der Unterschied zwischen let und const besteht darin, dass const-Variablen mit einem Initialisierer deklariert werden müssen, da sonst ein Fehler generiert wird.

Und schließlich werden beim Ausführungskontext mit var definierte Variablen an das Objekt 'this' angehängt. Im globalen Ausführungskontext ist dies das Fensterobjekt in Browsern. Dies ist bei let oder const nicht der Fall.

Donato
quelle
2

Ich denke, die Begriffe und die meisten Beispiele sind etwas überwältigend. Das Hauptproblem, das ich persönlich mit dem Unterschied hatte, ist zu verstehen, was ein "Block" ist. Irgendwann wurde mir klar, dass ein Block alle geschweiften Klammern außer der IFAnweisung sein würde. Eine öffnende Klammer {einer Funktion oder Schleife definiert einen neuen Block. Alles, was darin definiert letist, ist nach der schließenden Klammer }derselben Sache (Funktion oder Schleife) nicht verfügbar . In diesem Sinne war es einfacher zu verstehen:

let msg = "Hello World";

function doWork() { // msg will be available since it was defined above this opening bracket!
  let friends = 0;
  console.log(msg);

  // with VAR though:
  for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
  console.log(iCount2);
  
    for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
  console.log(iCount1);
  
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);

Dementic
quelle
1

Jetzt denke ich, dass es ein besseres Scoping von Variablen für einen Anweisungsblock gibt, indem let:

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

Ich denke, die Leute werden let hier später verwenden, damit sie einen ähnlichen Umfang in JavaScript haben wie andere Sprachen, Java, C # usw.

Menschen, die kein klares Verständnis für das Scoping in JavaScript haben, haben den Fehler früher gemacht.

Das Heben wird mit nicht unterstützt let.

Mit diesem Ansatz werden in JavaScript vorhandene Fehler entfernt.

Siehe ES6 im Detail: let und const , um es besser zu verstehen.

Swaraj Patil
quelle
Für ein detailliertes
swaraj patil
1

Dieser Artikel definiert klar den Unterschied zwischen var, let und const

const ist ein Signal, dass die Kennung nicht neu zugewiesen wird.

letist ein Signal, dass die Variable neu zugewiesen werden kann, z. B. ein Zähler in einer Schleife oder ein Wertetausch in einem Algorithmus. Es signalisiert auch, dass die Variable nur in dem Block verwendet wird, in dem sie definiert ist. Dies ist nicht immer die gesamte enthaltende Funktion.

varist jetzt das schwächste verfügbare Signal, wenn Sie eine Variable in JavaScript definieren. Die Variable kann neu zugewiesen werden oder nicht, und die Variable kann für eine gesamte Funktion oder nur zum Zweck eines Blocks oder einer Schleife verwendet werden oder nicht.

https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b

Anandharshan
quelle