it-swarm-eu.dev

Was ist der Unterschied zwischen "let" und "var", um eine Variable in JavaScript zu deklarieren?

ECMAScript 6 hat die let-Anweisung eingeführt. Ich habe gehört, dass es als "lokale" Variable beschrieben wird, aber ich bin immer noch nicht ganz sicher, wie es sich anders verhält als das Schlüsselwort var.

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

3680
TM.

Der Unterschied ist der Umfang. var ist auf den nächstgelegenen Funktionsblock und let auf den nächsten einschließenden Block beschränkt, der kleiner als ein Funktionsblock sein kann. Beide sind global, wenn sie sich außerhalb eines Blocks befinden.

Mit let deklarierte Variablen sind auch nicht zugänglich, bevor sie in ihrem umgebenden Block deklariert werden. Wie in der Demo zu sehen, wird eine ReferenceError-Ausnahme ausgelöst.

Demo : 

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Global:

Sie sind sehr ähnlich, wenn sie außerhalb eines Funktionsblocks verwendet werden.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

Mit let definierte globale Variablen werden jedoch nicht als Eigenschaften für das globale window-Objekt hinzugefügt, wie die mit var definierten.

console.log(window.me); // undefined
console.log(window.i); // 'able'

Funktion:

Sie sind identisch, wenn sie in einem Funktionsbaustein so verwendet werden.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Block:

Hier ist der Unterschied. let ist nur in der for()-Schleife sichtbar und var ist für die gesamte Funktion sichtbar.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Redeclaration:

Im strikten Modus können Sie mit var dieselbe Variable im selben Gültigkeitsbereich erneut deklarieren. Andererseits wird let nicht:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
5094
ThinkingStiff

let kann auch verwendet werden, um Probleme mit Verschlüssen zu vermeiden. Es bindet neue Werte, anstatt eine alte Referenz zu behalten, wie in den folgenden Beispielen gezeigt.

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

Der obige Code demonstriert ein klassisches Problem beim Schließen von JavaScript. Der Verweis auf die Variable i wird nicht im tatsächlichen Wert von i, sondern im Schließen des Click-Handlers gespeichert.

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

Eine allgemeine Problemumgehung besteht darin, dies in eine anonyme Funktion zu verpacken und i als Argument zu übergeben. Solche Probleme können jetzt auch vermieden werden, indem Sie let statt var verwenden, wie im folgenden Code gezeigt.

DEMO (In Chrome und Firefox 50 getestet)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}
505
Gurpreet Singh

Was ist der Unterschied zwischen let und var?

  • Eine mit einer var -Anweisung definierte Variable ist in der Funktion von Beginn der Funktion an bekannt.*
  • Eine mit einer let -Anweisung definierte Variable ist nur in dem Block bekannt, in dem sie von dem Moment an definiert wird, in dem sie definiert wird.**

Betrachten 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 sehen wir, dass unsere Variable j nur in der ersten for-Schleife bekannt ist, nicht jedoch davor und danach. Unsere Variable i ist jedoch in der gesamten Funktion bekannt.

Bedenken Sie auch, dass blockspezifische Variablen nicht bekannt sind, bevor sie deklariert werden, da sie nicht angehoben werden. Es ist Ihnen auch nicht gestattet, dieselbe Blockbereichsvariable innerhalb desselben Blocks erneut zu deklarieren. Dadurch sind Variablen mit Block-Gültigkeitsbereich weniger fehleranfällig als Variablen mit globalem oder funktionalem Gültigkeitsbereich, die angehoben werden und bei Mehrfachdeklarationen keine Fehler verursachen.


Ist es sicher, let heute zu verwenden?

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

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

  • Wenn Sie serverseitigen JavaScript-Code schreiben ( Node.js ), können Sie die Anweisung let ohne Bedenken verwenden.

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

  • Wenn Sie clientseitigen JavaScript-Code schreiben und einen auf Node basierenden Transpiler verwenden (wie das traceur-Shell-Skript ​​ oder Babel ), können Sie die Anweisung let ohne Bedenken verwenden, und da Ihr Browser nur über den transpilierten Code Bescheid weiß, treten Leistungseinbußen auf sollte begrenzt sein.

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

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

Support table


So behalten Sie den Überblick über die Browser-Unterstützung

Eine aktuelle Übersicht darüber, welche Browser die let -Anweisung zum Zeitpunkt des Lesens dieser Antwort unterstützen, finden Sie unter this Can I Use Seite .


*  Variablen mit globalem und funktionalem Gültigkeitsbereich können initialisiert und verwendet werden, bevor sie deklariert werden, da JavaScript-Variablen hoisted . Dies bedeutet dass Erklärungen immer ganz oben im Geltungsbereich stehen.

**  Blockbereichsvariablen werden nicht gehisst

150
John Slegers

Hier ist eine Erklärung des let-Schlüsselworts mit einigen Beispielen.

lass sehr wie var arbeiten. Der Hauptunterschied besteht darin, dass der Gültigkeitsbereich einer var-Variablen 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.

138
Ben S

Der akzeptierten Antwort fehlt ein Punkt:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
104
Lcf.vs

let

Bereich blockieren

Variablen, die mit dem Schlüsselwort let deklariert werden, haben einen Blockbereich, dh sie sind nur in block verfügbar, in dem sie deklariert wurden.

Auf oberster Ebene (außerhalb einer Funktion)

Auf der obersten Ebene erstellen mit let 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

In einer Funktion

Innerhalb einer Funktion (aber außerhalb eines Blocks) hat let denselben Gültigkeitsbereich 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 mit let innerhalb 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 let in 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.

Loops mit Verschlüssen

Wenn Sie in einer Schleife let anstelle von var verwenden, erhalten Sie bei jeder Wiederholung eine neue Variable. Das bedeutet, dass Sie einen Verschluss innerhalb einer Schleife sicher 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);
}

Temporale Totzone

Aufgrund von der temporären Totzone kann auf Variablen, die mit let deklariert wurden, nicht vor ihrer Deklaration zugegriffen werden. Wenn Sie dies versuchen, wird ein Fehler ausgegeben.

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

Keine erneute Deklaration

Sie können dieselbe Variable nicht mehrmals mit let deklarieren. Sie können auch keine Variable mit let mit derselben Kennung wie eine andere Variable deklarieren, die mit var deklariert wurde.

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

const ist let ziemlich ähnlich - es hat einen Blockbereich und hat TDZ. Es gibt jedoch zwei Dinge, die sich unterscheiden.

Keine Neuzuordnung

Mit const deklarierte Variablen können nicht erneut zugewiesen werden.

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

Beachten Sie, dass dies nicht bedeutet, dass der Wert unveränderlich ist. Ihre 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 Object.freeze() verwenden.

Initialisierung ist erforderlich

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

const a; // SyntaxError: Missing initializer in const declaration
59

Hier ist ein Beispiel für den Unterschied zwischen den beiden (Unterstützung gerade für Chrome gestartet): enter image description here

Wie Sie sehen, hat die Variable var j noch einen Wert außerhalb des Gültigkeitsbereichs der for-Schleife (Block Scope), die Variable let i ist jedoch außerhalb des Gültigkeitsbereichs der for-Schleife 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);

42
vlio20

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

z.B. Es gilt für den umgebenden Block. Sie existieren nicht, bevor sie deklariert werden usw.

Es ist jedoch erwähnenswert, dass let nur ein Teil neuerer Javascript-Implementierungen ist und unterschiedliche Grade von Browser-Unterstützung hat.

42
olliej

Der Hauptunterschied ist der Bereich Unterschied, während nur verfügbar sein kann innerhalb des Gültigkeitsbereichs kann es wie in der for-Schleife var sein Zugriff außerhalb der Schleife zum Beispiel. Aus der Dokumentation in MDN (Beispiele auch aus MDN):

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

Variablen, die mit deklariert wurden, haben als Gültigkeitsbereich den Block, in dem sie definiert sind, sowie alle darin 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 erstellt keine Eigenschaft für das globale Objekt. Zum Beispiel:

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

Bei Verwendung innerhalb eines Blocks 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. Es ist daher besser, sie mit Babel usw. auf ECMA5 zu übertragen. Weitere Informationen finden Sie unter babel website

22
Alireza
  • Variable wird nicht angehoben

    let wird nicht gehoben auf den gesamten Gültigkeitsbereich des Blocks, in dem sie erscheinen, angewendet. Im Gegensatz dazu könnte var wie folgt hochgezogen werden.

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

    Tatsächlich werden pro @Bergi, sowohl var als auch let angehoben .

  • Müllsammlung

    Der Blockbereich von let ist nützlich für Schließungen und die Speicherbereinigung, um Speicher freizugeben. Erwägen,

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

    Der click-Handler-Callback benötigt die Variable hugeData nicht. Theoretisch könnte die riesige Datenstruktur hugeData nach der Ausführung von process(..) Müllsammlung sein. Es ist jedoch möglich, dass einige JS-Engines diese riesige Struktur beibehalten müssen, da die click-Funktion über den gesamten Gültigkeitsbereich geschlossen ist.

    Der Blockbereich kann jedoch dazu führen, dass diese riesige Datenstruktur in den gesammelten Müll umgewandelt 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 loops

    let in der Schleife kann bindet sie erneut an jede Iteration der Schleife an und stellt sicher, 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 var durch let

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

    Da let eine neue lexikalische Umgebung mit diesen Namen für a) den Initialisiererausdruck b) bei jeder Iteration (vorwiegend zur Auswertung des Inkrementausdrucks) erstellt, sind hier weitere Details.

20
zangw

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, adderFunctions mit einer Schleife unter Verwendung des Schlüsselworts var zu generieren, funktioniert nicht so, wie es jemand naiv erwarten könnte:

// 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 Array von Funktionen, da der Gültigkeitsbereich von i über die Iteration des for -Blocks hinausgeht, in dem die einzelnen Funktionen erstellt wurden. Stattdessen bezieht sich am Ende der Schleife das i in der Schließung jeder Funktion auf den Wert von i 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 i aktualisieren, wirkt sich die Mutation auf alle adderFunctions aus.

Wir können es jedoch erneut mit dem Schlüsselwort let 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 wird i bei jeder Iteration der for -Schleife neu gebunden. Jede Funktion behält jetzt den Wert von i zum Zeitpunkt der Erstellung der Funktion bei, und adderFunctions verhält sich wie erwartet.

Wenn Sie nun die beiden Verhaltensweisen im Bild mischen, werden Sie wahrscheinlich sehen, warum es nicht empfohlen wird, die neueren let und const mit den älteren var im selben Skript zu mischen. Dies kann zu etwas spektakulärem 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 Verhalten von var/let in Schleifen und mit Funktionsabschlüssen demonstrieren soll, die auch 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.

16
abroz

Funktionsumfang VS-Baustein:

Der Hauptunterschied zwischen var und let besteht darin, dass Variablen, die mit var deklariert wurden, den Funktionsumfang haben . Während mit let deklarierte Funktionen einen Blockumfang haben . 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 testVar aufgerufen wird, ist die mit var deklarierte Variable foo auch außerhalb der Anweisung if noch verfügbar. Diese Variable foo wäre im Rahmen des testVar überall verfügbar Funktion .

Variablen mit let:

Wenn die zweite Funktion testLet aufgerufen wird, ist die mit let deklarierte Variablenleiste nur innerhalb der Anweisung if zugänglich. Weil Variablen, die mit let deklariert wurden, blockweise sind (wobei ein Block der Code in geschweiften Klammern ist, z. B. if{}, for{}, function{}).

let Variablen werden nicht gehisst:

Ein weiterer Unterschied zwischen var und let besteht darin, dass Variablen, die mit let deklariert wurden , nicht hochgezogen werden . . Ein Beispiel veranschaulicht dieses Verhalten am besten:

variablen mit let werden nicht gehisst:

console.log(letVar);

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

variablen mit var werden gehisst:

console.log(varVar);

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

Globales let wird nicht an window angehängt:

Eine Variable, die im globalen Bereich mit let deklariert wurde (dh Code, der sich nicht in einer Funktion befindet), wird nicht als Eigenschaft zum globalen Objekt window hinzugefügt. Zum Beispiel (dieser Code ist 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 anstelle von var verwendet werden?

Verwenden Sie let über var, wann 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. var kann verwendet werden, wenn eine globale Variable explizit auf dem Objekt window stehen soll (immer sorgfältig prüfen, ob dies wirklich erforderlich ist).

11

Der Unterschied liegt im scope der mit jeder deklarierten Variablen.

In der Praxis hat der unterschiedliche Umfang eine Reihe nützlicher Konsequenzen:

  1. let-Variablen sind nur in ihrem nächstgelegenen einschließenden-Block ({ ... }) sichtbar.
  2. let-Variablen sind nur in Codezeilen verwendbar, die auftreten after die Variable ist deklariert (obwohl sie werden angehoben !).
  3. let-Variablen dürfen nicht durch eine nachfolgende var oder let neu deklariert werden.
  4. Globale Variablen let werden nicht zum globalen Objekt window hinzugefügt.
  5. let-Variablen sind einfach zu verwenden mit Schließungen (sie verursachen keine Race-Bedingungen ).

Die durch let auferlegten Einschränkungen verringern die Sichtbarkeit der Variablen und erhöhen die Wahrscheinlichkeit, dass unerwartete Namenskollisionen früh gefunden werden. Dies erleichtert die Nachverfolgung und Begründung von Variablen, einschließlich ihrer Erreichbarkeit (bei der Rückforderung nicht genutzten Speichers).

let-Variablen verursachen daher weniger Probleme, wenn sie in großen Programmen verwendet werden oder wenn unabhängig entwickelte Frameworks auf neue und unerwartete Weise kombiniert werden.

var kann dennoch nützlich sein, wenn Sie sicher sind, dass Sie den Single-Binding-Effekt bei der Verwendung eines Abschlusses in einer Schleife (# 5) oder zum Deklarieren von extern sichtbaren globalen Variablen in Ihrem Code (# 4) verwenden möchten. Die Verwendung von var für Exporte kann ersetzt werden, wenn export außerhalb des Transpilerraums in die Kernsprache migriert wird.

Beispiele

1. Keine Verwendung außerhalb des nächstgelegenen umgebenden Blocks: Dieser Codeblock löst einen Referenzfehler aus, da die zweite Verwendung von x außerhalb des Blocks erfolgt, in dem er mit let: .__ deklariert ist.

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

Im Gegensatz dazu funktioniert das gleiche Beispiel mit var.

2. Keine Verwendung vor der Deklaration:
Dieser Code-Block wirft eine ReferenceError, bevor der Code ausgeführt werden kann, da x verwendet wird, 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 wird dasselbe Beispiel mit var analysiert und ohne Ausnahmen ausgeführt.

3. Keine Redeclaration: Der folgende Code zeigt, dass eine mit let deklarierte Variable später nicht erneut deklariert werden kann: 

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

4. Globals nicht an window gebunden:

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 var deklarierte Variablen funktionieren nicht gut mit Verschlüssen in Schleifen. Hier ist eine einfache Schleife, die die Folge von Werten ausgibt, die die Variable i zu verschiedenen Zeitpunkten hat: 

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

Dies gibt insbesondere Folgendes aus:

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

In JavaScript verwenden wir Variablen zu einem wesentlich späteren Zeitpunkt als bei ihrer Erstellung. Wenn wir dies demonstrieren, indem wir die Ausgabe mit einem an setTimeout übergebenen Abschluss verzögern: 

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

... die Ausgabe bleibt unverändert, solange wir bei let bleiben. Wenn wir dagegen var i verwendet hätten: 

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

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

i is 5
i is 5
i is 5
i is 5
i is 5
11
mormegil

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
}
10
Abdennour TOUMI

let ist interessant, weil wir so etwas tun können:

(() => {
    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 führt zum Zählen [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].

10
Dmitry

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

Dies erzeugt keinen Kompilierungsfehler:

var x = 1;
var x = 2;

Dieser Wille:

let x = 1;
let x = 2;
6
RDoc

var ist globale (hoistfähige) Variable.

let und const ist der 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

5

Bei Verwendung von let

Das Schlüsselwort let hängt die Variablendeklaration an den Gültigkeitsbereich des Blocks an (in der Regel ein { .. }-Paar), in dem er enthalten ist. Mit anderen Worten: let übernimmt implizit den Gültigkeitsbereich jedes Blocks für seine Variablendeklaration.

Auf let-Variablen kann nicht im window-Objekt 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

Bei Verwendung von var

var and variables in ES5 hat Gültigkeitsbereiche in Funktionen, dh die Variablen sind innerhalb der Funktion gültig und nicht außerhalb der Funktion selbst.

Auf var-Variablen kann im window-Objekt 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 wollen, lesen Sie weiter unten

eine der bekanntesten Interviewfragen zum Umfang kann auch für die genaue Verwendung von let und var wie unten genügen.

Bei Verwendung von 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, dass bei Verwendung von let für jede Schleifeniteration die Variable einen Bereich hat und über eine eigene Kopie verfügt.

Bei Verwendung von 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 von var für jede Schleifeniteration die Variable einen Gültigkeitsbereich hat und eine gemeinsam genutzte Kopie hat.

4
Ankur Soni

Wenn ich die Spezifikationen richtig gelesen habe, kann letdankbar auch verwendet werden, um zu vermeiden, dass selbst aufgerufene Funktionen verwendet werden, um nur private Mitglieder zu simulieren - ein beliebtes Entwurfsmuster, das die Lesbarkeit von Code verringert, das Debuggen kompliziert, fügt hinzu Kein echter Code-Schutz oder sonstiger Vorteil - außer, dass Sie vielleicht den Wunsch nach Semantik befriedigen, hören Sie damit auf./rant

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 ' Private Schnittstellen emulieren '

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)
3
zloctb

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
}
2
vipul jain

Bisher gab es in JavaScript nur zwei Bereiche, d. H. Funktional und global. Mit dem Schlüsselwort 'let' hat JavaScript jetzt block-level-Variablen eingeführt.

Um ein umfassendes Verständnis des Schlüsselworts "let" zu erhalten, hilft ES6: Das Schlüsselwort "let" zum Deklarieren der Variablen in JavaScript hilft.

1
Hitesh Garg

In diesem Artikel wird der Unterschied zwischen var, let und const klar definiert

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

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

var ist jetzt das schwächste Signal, das zur Verfügung steht, wenn Sie eine Variable definieren in JavaScript. Die Variable kann neu zugewiesen werden oder nicht und das Variable kann für eine gesamte Funktion oder nur für .__ verwendet werden oder nicht. der Zweck eines Blocks oder einer Schleife.

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

1
anandharshan

Jetzt denke ich, dass es einen besseren Bereich von Variablen für einen Anweisungsblock gibt, der let verwendet:

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, dass die Leute hier anfangen werden, so dass sie einen ähnlichen Umfang in JavaScript haben wie andere Sprachen, Java, C # usw.

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

Das Hochziehen wird nicht mit let unterstützt.

Mit diesem Ansatz werden Fehler in JavaScript entfernt. 

Siehe ES6 In Depth: let und const, um es besser zu verstehen.

1
swaraj patil

let vs var. Es geht nur um Umfang .

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

Sehen Sie sich mein Beispiel unten an und beachten Sie, wie sich die lion (let) -Variable in den beiden console.logs unterschiedlich verhält. In der zweiten Datei console.log wird es ungültig.

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.
1
daCoda

Wie oben erwähnt:

Der Unterschied ist der Umfang. var ist auf die nächste Funktion beschränkt block und let sind auf den nächstgelegenen umgebenden Block beschränkt, der kann kleiner als ein Funktionsblock sein. Beide sind global, wenn sie außerhalb von .__ liegen. block.Lets sehen ein Beispiel:

Beispiel 1:

In meinen beiden Beispielen habe ich eine Funktion myfunc. myfunc enthält eine Variable myvar entspricht 10. In meinem ersten Beispiel überprüfe ich, ob myvar 10 (myvar==10) entspricht. Wenn ja, deklariere ich eine Variable myvar (jetzt habe ich zwei myvar-Variablen) mit dem var-Schlüsselwort und weise einen neuen Wert (20) zu. In der nächsten Zeile drucke ich den Wert auf meiner Konsole. Nach dem Bedingungsblock drucke ich erneut den Wert von myvar auf meiner Konsole. Wenn Sie sich die Ausgabe von myfunc anschauen, hat myvar einen Wert von 20. 

 let keyword

Example2: In meinem zweiten Beispiel deklariere ich anstelle von var in meinem Bedingungsblock myvar mit let. Wenn ich jetzt myfunc anrufe, bekomme ich zwei verschiedene Ausgaben: myvar=20 und myvar=10.

Der Unterschied ist also sehr einfach, d. H. Der Umfang. 

1
N Randhawa

 enter image description here

Werfen Sie einen Blick auf dieses Bild. Ich habe ein sehr einfaches Beispiel für die Demonstration der Variablen const und let erstellt. Wenn Sie versuchen, die Variable const zu ändern, wird der Fehler angezeigt (Versuch, 'name' zu überschreiben, was konstant ist). Sehen Sie sich jedoch die Variable let an ... 

Zuerst deklarieren wir let age = 33 und weisen später einen anderen Wert age = 34; zu. Dies ist in Ordnung. Wir haben keine Fehler, wenn wir versuchen, die Variable let zu ändern

0
Mile Mijatovic

Ich möchte diese Schlüsselwörter mit dem Ausführungskontext verknüpfen, da der Ausführungskontext dabei von Bedeutung ist. Der Ausführungskontext besteht aus zwei Phasen: einer Erstellungsphase und einer Ausführungsphase. Zusätzlich hat jeder Ausführungskontext 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 mit einem undefinierten Wert im Variablenumfeld 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 erst dann auf die mit let oder const deklarierte Variable verweisen, wenn sie deklariert ist. Wenn Sie versuchen, es zu verwenden, bevor es deklariert wurde, wird während der Ausführungsphase des Ausführungskontexts eine Ausnahme ausgelöst. Die Variable befindet sich weiterhin im Speicher, dank der Erstellungsphase des Ausführungskontextes, aber Sie können sie von der Engine nicht verwenden:

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

Wenn die Engine bei einer mit var definierten Variablen die Variable in der Variablenumgebung des aktuellen Ausführungskontexts nicht finden kann, wird sie in der Scope-Kette (der äußeren Umgebung) nach oben verschoben und die Variablenumgebung der äußeren Umgebung auf die Variable überprüft. Wird es dort nicht gefunden, wird die Suche in der Scope-Kette fortgesetzt. Dies ist bei let und const nicht der Fall.

Das zweite Merkmal von let ist die Einführung in den Blockumfang. 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 erstellt der Block bei jeder Ausführung, z. B. innerhalb einer for-Schleife, eine neue Variable im Speicher.

ES6 führt auch das Schlüsselwort const zum Deklarieren von Variablen ein. const ist ebenfalls blockspezifisch. Der Unterschied zwischen let und const besteht darin, dass const-Variablen mithilfe eines Initialisierers deklariert werden müssen. Andernfalls wird ein Fehler generiert.

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

0
Donato

Ich denke, die Begriffe und die meisten Beispiele sind etwas überwältigend. Das Hauptproblem, das ich persönlich mit dem Unterschied hatte, ist das Verstehen, was ein "Block" ist. Irgendwann wurde mir klar, dass ein Block keine geschweiften Klammern außer der Anweisung IF sind. eine öffnende Klammer { einer Funktion oder Schleife definiert einen neuen Block, alles, was mit let definiert ist, ist nicht verfügbar, nachdem die schließende Klammer } der gleichen Sache (Funktion oder Schleife); 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);
0
Dementic

Da ich momentan versuche, mir ein umfassendes Verständnis von JavaScript anzueignen, werde ich meine kurze Recherche vorstellen, die einige der bereits besprochenen großartigen Arbeiten sowie einige weitere Details aus einer anderen Perspektive enthält.

Das Verstehen des Unterschieds zwischen var und let kann einfacher sein, wenn wir den Unterschied zwischen function und block scope verstehen.

Betrachten wir die folgenden Fälle:

(function timer() {
    for(var i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();


   Stack            VariableEnvironment //one VariablEnvironment for timer();
                                       // when the timer is out - the value will be the same value for each call
5. [setTimeout, i]  [i=5] 
4. [setTimeout, i]  
3. [setTimeout, i]
2. [setTimeout, i]
1. [setTimeout, i]
0. [setTimeout, i]

####################    

(function timer() {
    for (let i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();

   Stack           LexicalEnvironment - each iteration has a new lexical environment
5. [setTimeout, i]  [i=5]       
                      LexicalEnvironment 
4. [setTimeout, i]    [i=4]     
                        LexicalEnvironment 
3. [setTimeout, i]      [i=3]       
                         LexicalEnvironment 
2. [setTimeout, i]       [i=2]
                           LexicalEnvironment 
1. [setTimeout, i]         [i=1]
                             LexicalEnvironment 
0. [setTimeout, i]           [i=0]

wenn timer() aufgerufen wird, wird ein ExecutionContext erstellt, der sowohl die VariableEnvironment als auch alle LexicalEnvironments für jede Iteration enthält.

Und ein einfacheres Beispiel

Funktionsumfang

function test() {
    for(var z = 0; z < 69; z++) {
        //todo
    }
    //z is visible outside the loop
}

Gültigkeitsbereich blockieren

function test() {
    for(let z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}
0
Lucian Nut