Qual è la differenza tra l'utilizzo di "let" e "var"?


4545

Introduzione di ECMAScript 6 la letdichiarazione .

Ho sentito che è descritto come una variabile "locale", ma non sono ancora del tutto sicuro di come si comporti diversamente dalla var parola chiave.

Quali sono le differenze? Quando dovrebbe letessere usato var?


105
ECMAScript è lo standard ed letè incluso nella bozza della sesta edizione e molto probabilmente sarà nella specifica finale.
Richard Ayotte,

5
Vedere kangax.github.io/es5-compat-table/es6 per una matrice di supporto aggiornata delle funzionalità ES6 (incluso let). Al momento della stesura di Firefox, Chrome e IE11 lo supportano tutti (anche se credo che l'implementazione di FF non sia del tutto standard).
Nico Burns,

22
Per molto tempo non sapevo che i var in un ciclo for erano mirati alla funzione in cui era racchiuso. Ricordo di averlo capito per la prima volta e ho pensato che fosse molto stupido. Vedo un po 'di potere sebbene sappia ora come i due potrebbero essere usati per ragioni diverse e come in alcuni casi potresti voler usare una var in un ciclo for e non averla portata al blocco.
Eric Bishard,

1
Questa è un'ottima lettura wesbos.com/javascript-scoping
onmyway133

Risposte:


6102

Regole di scoping

La differenza principale sono le regole di scoping. Le variabili dichiarate dalla varparola chiave sono indirizzate al corpo della funzione immediata (da qui l'ambito della funzione) mentre le letvariabili sono portate al blocco di chiusura immediato indicato da { }( da qui l'ambito del blocco).

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

  console.log(foo, bar);

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

  console.log(baz); // ReferenceError
}

run();

Il motivo per cui la letparola chiave è stata introdotta nel linguaggio era l'ambito della funzione è confuso ed è stata una delle principali fonti di bug in JavaScript.

Dai un'occhiata a questo esempio da un'altra domanda di StackOverflow :

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: 3 è stato emesso per console ogni volta funcs[j](); veniva invocato poiché le funzioni anonime erano legate alla stessa variabile.

Le persone dovevano creare immediatamente funzioni invocate per catturare il valore corretto dagli anelli ma che era anche peloso.

sollevamento

Mentre le variabili dichiarate con la varparola chiave vengono sollevate (inizializzate con undefinedprima dell'esecuzione del codice), ciò significa che sono accessibili nel loro ambito di appartenenza anche prima che vengano dichiarate:

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

run();

letle variabili non vengono inizializzate fino a quando non viene valutata la loro definizione. Accedendoli prima dell'inizializzazione si ottiene un ReferenceError. La variabile si dice che si trovi nella "zona morta temporale" dall'inizio del blocco fino a quando l'inizializzazione non viene elaborata.

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

checkHoisting();

Creazione della proprietà dell'oggetto globale

Al livello superiore let, a differenza di var, non crea una proprietà sull'oggetto globale:

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

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

ridichiarazione

In modalità rigorosa, varti consente di ri-dichiarare la stessa variabile nello stesso ambito mentre letgenera un SyntaxError.

'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

23
Ricorda che puoi creare blocchi quando vuoi. function () {code; {let inBlock = 5; } codice; };
media Joe

177
Quindi lo scopo di lasciare che le istruzioni liberino memoria solo quando non sono necessarie in un determinato blocco?
NoBugs,

219
@NoBugs, Sì, ed è incoraggiato che le variabili siano presenti solo dove sono necessarie.
Batman,

67
letl'espressione di blocco let (variable declaration) statementnon è standard e verrà rimossa in futuro, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus,

19
Quindi, non riesco proprio a pensare a nessun caso in cui l'uso di var sia di qualche utilità. Qualcuno potrebbe darmi un esempio di una situazione in cui è preferibile usare var?
Luis Sieira,

622

letpuò anche essere usato per evitare problemi con le chiusure. Associa un valore nuovo anziché mantenere un vecchio riferimento, come mostrato negli esempi seguenti.

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>

Il codice sopra mostra un classico problema di chiusura JavaScript. Il riferimento alla ivariabile viene archiviato nella chiusura del gestore di clic, anziché il valore effettivo di i.

Ogni gestore di clic singolo farà riferimento allo stesso oggetto perché esiste un solo oggetto contatore che contiene 6, quindi ne ottieni sei per ogni clic.

Una soluzione generale è quella di avvolgerlo in una funzione anonima e passare icome argomento. Tali problemi possono anche essere evitati ora usando letinvece varcome mostrato nel codice seguente.

(Testato su Chrome e 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>


54
Questo è davvero bello. Mi aspetto che "i" sia definito al di fuori del corpo del loop racchiuso tra parentesi e NON formi una "chiusura" attorno a "i". Ovviamente il tuo esempio dimostra il contrario. Penso che sia un po 'confuso dal punto di vista della sintassi, ma questo scenario è così comune che ha senso supportarlo in quel modo. Mille grazie per averlo sollevato.
Karol Kolenda,

9
IE 11 supporta let, ma avvisa "6" per tutti i pulsanti. Hai qualche fonte che dice come letdovrebbe comportarsi?
Jim Hunziker,

10
Sembra che la tua risposta sia il comportamento corretto: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker,

11
In effetti questa è una trappola comune in Javascript e ora posso vedere perché letsarebbe davvero utile. L'impostazione dei listener di eventi in un ciclo non richiede più un'espressione di funzione richiamata immediatamente per l'ambito locale iad ogni iterazione.
Adrian Moisa,

19
L'uso di "let" difende questo problema. Pertanto, ogni iterazione crea un ambito di blocco indipendente privato, ma la variabile "i" può ancora essere danneggiata da successive modifiche all'interno del blocco, (a condizione che la variabile iteratore non venga solitamente modificata all'interno del blocco, ma altre variabili let dichiarate all'interno del blocco potrebbero anche be) e qualsiasi funzione dichiarata all'interno del blocco lattina, quando viene richiamato, corrompere il valore di "i" per altre funzioni dichiarata all'interno del blocco perché fanno condividono la stessa portata blocco privato quindi lo stesso riferimento alla "i".
gary,

199

Qual è la differenza tra lete var?

  • Una variabile definita utilizzando varun'istruzione è nota in tutta la funzione in cui è definita, dall'inizio della funzione. (*)
  • Una variabile definita usando letun'istruzione è nota solo nel blocco in cui è definita, dal momento in cui è definita in poi. (**)

Per capire la differenza, considera il seguente codice:

// 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

Qui, possiamo vedere che la nostra variabile jè nota solo nel primo ciclo, ma non prima e dopo. Tuttavia, la nostra variabile iè nota nell'intera funzione.

Inoltre, considerare che le variabili con ambito di blocco non sono note prima di essere dichiarate perché non vengono issate. Inoltre, non è possibile dichiarare nuovamente la stessa variabile con ambito blocco all'interno dello stesso blocco. Ciò rende le variabili con ambito di blocco meno soggette a errori rispetto alle variabili con ambito globale o funzionale, che vengono sollevate e che non generano errori in caso di dichiarazioni multiple.


È sicuro da usare let oggi?

Alcune persone sostengono che in futuro utilizzeremo SOLO le dichiarazioni let e che le dichiarazioni var diventeranno obsolete. Il guru di JavaScript Kyle Simpson ha scritto un articolo molto elaborato sul perché crede che non sarà così .

Oggi, tuttavia, non è assolutamente così. In effetti, dobbiamo effettivamente chiederci se è sicuro utilizzare la letdichiarazione. La risposta a questa domanda dipende dal tuo ambiente:

  • Se stai scrivendo codice JavaScript sul lato server ( Node.js ), puoi tranquillamente utilizzare l' letistruzione.

  • Se stai scrivendo codice JavaScript sul lato client e usi un transpiler basato su browser (come Traceur o babel-standalone ), puoi tranquillamente utilizzare la letdichiarazione, tuttavia è probabile che il tuo codice sia tutt'altro che ottimale rispetto alle prestazioni.

  • Se stai scrivendo codice JavaScript sul lato client e usi un transpiler basato su Nodo (come lo script della shell traceur o Babel ), puoi tranquillamente usare l' letistruzione. E poiché il tuo browser conoscerà solo il codice traspilato, gli svantaggi delle prestazioni dovrebbero essere limitati.

  • Se stai scrivendo codice JavaScript lato client e non usi un transpiler, devi considerare il supporto del browser.

    Esistono ancora alcuni browser che non supportano letaffatto:

inserisci qui la descrizione dell'immagine


Come tenere traccia del supporto del browser

Per una panoramica aggiornata di quali browser supportano la letdichiarazione al momento della lettura di questa risposta, consultare questa Can I Usepagina .


(*) Le variabili con portata globale e funzionale possono essere inizializzate e utilizzate prima di essere dichiarate perché le variabili JavaScript vengono issate .Ciò significa che le dichiarazioni sono sempre in cima all'ambito.

(**) Le variabili con ambito di blocco non vengono sollevate


14
per quanto riguarda la risposta v4: iÈ noto ovunque nel blocco funzione! Inizia come undefined(a causa di sollevamento) fino a quando non si assegna un valore! ps: letviene anche sollevato (all'inizio del blocco contenente), ma darà un ReferenceErrorriferimento quando nel blocco prima della prima assegnazione. (ps2: sono un tipo pro-punto e virgola ma non hai davvero bisogno di un punto e virgola dopo un blocco). Detto questo, grazie per aver aggiunto il controllo della realtà per quanto riguarda il supporto!
GitaarLAB,

@GitaarLAB: Secondo la rete di sviluppatori Mozilla : "In ECMAScript 2015, lasciare che i binding non siano soggetti a sollevamento variabile, il che significa che le dichiarazioni non si spostano all'inizio del contesto di esecuzione corrente". - Comunque, ho apportato alcuni miglioramenti alla mia risposta che dovrebbe chiarire la differenza nel comportamento di sollevamento tra lete var!
John Slegers,

1
La tua risposta è migliorata molto (ho controllato attentamente). Nota che lo stesso link a cui hai fatto riferimento nel tuo commento dice anche: "La variabile (let) è in una" zona morta temporale " dall'inizio del blocco fino a quando l'inizializzazione non viene elaborata." Ciò significa che l '"identificatore" (la stringa di testo "riservata" per indicare "qualcosa") è già riservato nell'ambito pertinente, altrimenti diventerebbe parte dell'ambito radice / host / finestra. Personalmente, "sollevamento" non significa altro che riservare / collegare "identificatori" dichiarati al loro ambito pertinente; escludendo la loro inizializzazione / assegnazione / modificabilità!
GitaarLAB

E .. + 1. Quell'articolo di Kyle Simpson che hai collegato è un'ottima lettura, grazie per quello! È anche chiaro sulla "zona morta temporale" alias "TDZ". Una cosa interessante che vorrei aggiungere: l'ho letto su MDN lete mi è conststato consigliato di usarlo solo quando in realtà hai bisogno della loro funzionalità aggiuntiva , perché l'applicazione / il controllo di queste funzionalità extra (come la const di sola scrittura) si traduce in 'più lavoro "(e nodi di ambito aggiuntivi nella struttura di ambito) per i motori (attuali) da applicare / controllare / verificare / configurare.
GitaarLAB

1
Nota che MDN afferma che IE DOES interpreta correttamente. Cos'è questo? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka Hesselink

146

Ecco una spiegazione della letparola chiave con alcuni esempi.

letfunziona molto bene var. La differenza principale è che l'ambito di una varvariabile è l'intera funzione racchiusa

Questa tabella su Wikipedia mostra quali browser supportano Javascript 1.7.

Nota che solo i browser Mozilla e Chrome lo supportano. IE, Safari e potenzialmente altri no.


5
Il bit chiave del testo del documento collegato sembra essere "lascia che funzioni in modo molto simile a var. La differenza principale è che l'ambito di una variabile var è l'intera funzione racchiusa".
Michael Burr,

50
Mentre è tecnicamente corretto dire che IE non lo supporta, è più corretto dire che è un'estensione solo mozilla.
olliej,

55
@olliej, in realtà Mozilla è appena in vantaggio. Vedi pagina 19 di ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton,

@TylerCrompton è solo l'insieme di parole riservate da anni. Quando mozilla ha aggiunto, lascia che fosse puramente un'estensione mozilla, senza specifiche correlate. ES6 dovrebbe definire il comportamento delle dichiarazioni let, ma ciò è arrivato dopo che Mozilla ha introdotto la sintassi. Ricorda che moz ha anche E4X, che è completamente morto e solo moz.
olliej,


112

Alla risposta accettata manca un punto:

{
  let a = 123;
};

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

19
La risposta accettata NON spiega questo punto nel suo esempio. La risposta accettata l'ha dimostrata solo in un forinizializzatore di loop, riducendo drasticamente il campo di applicazione dei limiti di let. Upvoted.
Jon Davis,

37
@ stimpy77 Dichiara esplicitamente "let is scoped to the next enclosure block"; deve essere incluso ogni modo che si manifesta?
Dave Newton,

6
ci sono stati molti esempi e nessuno di loro ha correttamente dimostrato la questione .. Avrei potuto annullare sia la risposta accettata che questa?
Jon Davis,

5
Questo contributo dimostra che un "blocco" può essere semplicemente un insieme di linee racchiuse tra parentesi; cioè non ha bisogno di essere associato ad alcun tipo di flusso di controllo, loop, ecc.
webelo

81

let

Ambito di blocco

Le variabili dichiarate utilizzando la letparola chiave hanno un ambito di blocco, il che significa che sono disponibili solo nel blocco in cui sono state dichiarate.

Al livello superiore (al di fuori di una funzione)

Al livello più alto, le variabili dichiarate usando letnon creano proprietà sull'oggetto globale.

var globalVariable = 42;
let blockScopedVariable = 43;

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

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

All'interno di una funzione

All'interno di una funzione (ma al di fuori di un blocco), letha lo stesso ambito di 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

All'interno di un blocco

Le variabili dichiarate usando letall'interno di un blocco non sono accessibili al di fuori di quel blocco.

{
  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

All'interno di un ciclo

Le variabili dichiarate con letin loop possono essere referenziate solo all'interno di quel loop.

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.

Passanti con chiusure

Se si utilizza letinvece che varin un ciclo, ad ogni iterazione si ottiene una nuova variabile. Ciò significa che puoi tranquillamente utilizzare una chiusura all'interno di un anello.

// 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);
}

Zona morta temporale

A causa della zona morta temporale , letnon è possibile accedere alle variabili dichiarate utilizzando prima di essere dichiarate. Tentare di farlo genera un errore.

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

Nessuna nuova dichiarazione

Non puoi dichiarare la stessa variabile più volte usando let. Inoltre, non è possibile dichiarare una variabile utilizzando letcon lo stesso identificativo di un'altra variabile dichiarata utilizzando 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

constè abbastanza simile a let- è a ambito di blocco e ha TDZ. Vi sono, tuttavia, due cose diverse.

Nessuna riassegnazione

La variabile dichiarata utilizzando constnon può essere riassegnata.

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

Si noti che ciò non significa che il valore sia immutabile. Le sue proprietà possono ancora essere modificate.

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

Se vuoi avere un oggetto immutabile, dovresti usare Object.freeze().

È richiesto l'inizializzatore

È sempre necessario specificare un valore quando si dichiara una variabile utilizzando const.

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

51

Ecco un esempio della differenza tra i due (supporto appena avviato per Chrome):
inserisci qui la descrizione dell'immagine

Come puoi vedere, la var jvariabile ha ancora un valore esterno all'ambito del ciclo for (Block Scope), ma la let ivariabile non è definita al di fuori dell'ambito del ciclo for.

"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);


2
Quale strumento sto guardando qui?
Barton,

20
Chrome devtools
vlio20

Come sviluppatore di applet desktop per Cinnamon, non sono stato esposto a strumenti così brillanti.
Barton,

48

Ci sono alcune sottili differenze: let ambito si comporta più come l'ambito variabile in più o meno in qualsiasi altra lingua.

ad es. si estende al blocco racchiuso, non esistono prima che vengano dichiarate, ecc.

Tuttavia, vale la pena notare che letè solo una parte delle più recenti implementazioni Javascript e ha vari gradi di supporto del browser .


11
Vale anche la pena notare che ECMAScript è lo standard ed letè incluso nella bozza della sesta edizione e molto probabilmente sarà nella specifica finale.
Richard Ayotte,

23
Questa è la differenza che fanno 3 anni: D
olliej

4
Mi sono appena imbattuto in questa domanda e nel 2012 è ancora supportato solo dai browser Mozilla let. Safari, IE e Chome non lo fanno.
pseudosavant,

2
L'idea di creare accidentalmente un ambito di blocco parziale in caso di incidente è un buon punto, attenzione, letnon si alza, per utilizzare una variabile definita da un letdefinito nella parte superiore del blocco. Se hai ifun'istruzione che è più di poche righe di codice, potresti dimenticare che non puoi usare quella variabile fino a quando non è stata definita. GRANDE PUNTO !!!
Eric Bishard,

2
@EricB: yes and no: "In ECMAScript 2015, let solleverò la variabile nella parte superiore del blocco. Tuttavia, facendo riferimento alla variabile nel blocco prima della dichiarazione della variabile si ottiene un ReferenceError (la mia nota: invece di un buon vecchio undefined). la variabile si trova in una "zona morta temporale" dall'inizio del blocco fino all'elaborazione della dichiarazione. " Lo stesso vale per "istruzioni switch perché esiste un solo blocco sottostante". Fonte: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB,

29

La differenza principale è la differenza dell'ambito , mentre let può essere disponibile solo all'interno dell'ambito che viene dichiarato, come ad esempio nel ciclo, var è accessibile al di fuori del ciclo, ad esempio. Dalla documentazione in MDN (esempi anche da MDN):

let permette di dichiarare le variabili che sono di portata limitata al blocco, dichiarazione o espressione su cui viene utilizzato. Questo è diverso dal var parola chiave , che definisce una variabile a livello globale o localmente per un'intera funzione indipendentemente dall'ambito del blocco.

Le variabili dichiarate da let hanno come scopo il blocco in cui sono definite, nonché in tutti i blocchi secondari contenuti. In questo modo, lascia che funzioni in modo molto simile a var . La differenza principale è che l'ambito di una variabile var è l'intera funzione che racchiude:

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
}`

Al livello superiore di programmi e funzioni, lasciare che , a differenza di var , non crea una proprietà sull'oggetto globale. Per esempio:

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

Se utilizzato all'interno di un blocco, limita l'ambito della variabile a quel blocco. Notare la differenza tra var il cui ambito è all'interno della funzione in cui è dichiarato.

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

Inoltre, non dimenticare la sua funzione ECMA6, quindi non è ancora completamente supportata, quindi è meglio traspilarla sempre in ECMA5 usando Babel ecc ... per maggiori informazioni su visita il sito web babel


24
  • Variabile non sollevata

    letsarà non paranco all'intero perimetro del blocco sono visualizzati. Per contro, varpotrebbe issare come sotto.

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

    In realtà, Per @Bergi, Entrambi vare letvengono issati .

  • Raccolta dei rifiuti

    L'ambito del blocco di letè utile riguarda le chiusure e la garbage collection per recuperare la memoria. Prendere in considerazione,

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

    Il clickcallback del gestore non necessita affatto della hugeDatavariabile. Teoricamente, dopo le process(..)esecuzioni, l'enorme struttura di dati hugeDatapotrebbe essere spazzata via. Tuttavia, è possibile che alcuni motori JS debbano mantenere questa struttura enorme, poiché la clickfunzione ha una chiusura su tutto l'ambito.

    Tuttavia, l'ambito del blocco può trasformare questa enorme struttura di dati in garbage collection.

    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 loop

    letnel ciclo può ricollegarlo a ciascuna iterazione del ciclo, assicurandosi di riassegnarlo al valore dalla fine dell'iterazione del ciclo precedente. Prendere in considerazione,

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

    Tuttavia, sostituire varconlet

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

    Perché letcreare un nuovo ambiente lessicale con quei nomi per a) l'espressione inizializzatore b) ogni iterazione (prima della valutazione dell'espressione dell'incremento), qui sono disponibili ulteriori dettagli .


4
Sì, vengono issati, ma si comportano come se non fossero stati sollevati a causa della zona morta temporale (rullo di tamburi) - un nome molto drammatico per un identificatore che non è accessibile fino a quando non viene dichiarato :-)
Drenai,

Quindi sia sollevato, ma non disponibile? In che modo è diverso da "non sollevato"?
N-ate

Speriamo che Brian o Bergi tornino per rispondere a questa domanda. Viene sollevata la dichiarazione di let, ma non l'incarico? Grazie!
N-ate

1
@ N-mangiato, ecco un post di Bergi, forse puoi trovare una risposta in esso.
zangw,

È interessante che si chiama anche sollevamento quando si tratta di lasciare. Capisco che tecnicamente il motore di analisi lo sta pre-catturando, ma a tutti gli effetti un programmatore dovrebbe trattarlo come se non esistesse. Il sollevamento di var ha invece implicazioni per un programmatore.
N-ate

19

Ecco un esempio da aggiungere a ciò che altri hanno già scritto. Supponiamo di voler creare una matrice di funzioni, in adderFunctionscui ciascuna funzione accetta un singolo argomento Number e restituisce la somma dell'argomento e l'indice della funzione nella matrice. Cercare di generare adderFunctionscon un ciclo usando la varparola chiave non funzionerà nel modo in cui qualcuno potrebbe ingenuamente aspettarsi:

// 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

Il processo sopra riportato non genera l'array di funzioni desiderato perché il'ambito si estende oltre l'iterazione del forblocco in cui è stata creata ciascuna funzione. Invece, alla fine del ciclo, la ichiusura di ciascuna funzione si riferisce al ivalore alla fine del ciclo (1000) per ogni funzione anonima in adderFunctions. Questo non è quello che volevamo affatto: ora abbiamo un array di 1000 diverse funzioni in memoria con esattamente lo stesso comportamento. E se successivamente aggiorniamo il valore di i, la mutazione influenzerà tutto il adderFunctions.

Tuttavia, possiamo riprovare utilizzando la letparola chiave:

// 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

Questa volta, iviene rimbalzato su ogni iterazione del forciclo. Ogni funzione ora mantiene il valore di ial momento della creazione della funzione eadderFunctions si comporta come previsto.

Ora, l'immagine mescola i due comportamenti e probabilmente vedrai perché non è consigliabile mescolare il più nuovo lete constil più vecchio varnello stesso script. Ciò può comportare un codice incredibilmente confuso.

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

Non lasciare che questo accada a te. Usa una linter.

NOTA: Questo è un esempio di insegnamento inteso a dimostrare il comportamento var/ letnei cicli e con chiusure di funzioni che sarebbero anche facili da capire. Questo sarebbe un modo terribile per aggiungere numeri. Ma la tecnica generale di acquisizione di dati in chiusure di funzioni anonime potrebbe essere incontrata nel mondo reale in altri contesti. YMMV.


2
@aborz: anche nel secondo esempio sintassi di funzioni anonime molto interessanti. È proprio quello a cui sono abituato in C #. Ho imparato qualcosa oggi.
Barton,

Correzione: tecnicamente, la sintassi della funzione freccia descritta qui => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton

3
In realtà, non è necessario let value = i;. L' foristruzione crea un blocco lessicale.
Spazzolino da denti

17

La differenza sta nella portata delle variabili dichiarate con ciascuna.

In pratica, ci sono una serie di conseguenze utili della differenza di portata:

  1. letle variabili sono visibili solo nel blocco di chiusura più vicino ({ ... } ).
  2. letle variabili sono utilizzabili solo nelle righe di codice che si verificano dopo che la variabile è stata dichiarata (anche se vengono issate !).
  3. letle variabili non possono essere dichiarate nuovamente da un successivo varo let.
  4. Le letvariabili globali non vengono aggiunte windowall'oggetto globale .
  5. letle variabili sono facili da usare con le chiusure (non causano condizioni di gara ).

Le restrizioni imposte da letriducono la visibilità delle variabili e aumentano la probabilità che collisioni di nomi impreviste vengano individuate in anticipo. Ciò semplifica il monitoraggio e la motivazione delle variabili, inclusa la loro raggiungibilità (aiutando a recuperare la memoria inutilizzata).

Di conseguenza, le letvariabili hanno meno probabilità di causare problemi quando vengono utilizzate in programmi di grandi dimensioni o quando i framework sviluppati in modo indipendente vengono combinati in modi nuovi e inaspettati.

varpuò essere comunque utile se sei sicuro di voler l'effetto di rilegatura singola quando usi una chiusura in un ciclo (# 5) o per dichiarare variabili globali visibili esternamente nel tuo codice (# 4). L'uso di varper le esportazioni può essere soppiantato se exportmigra dallo spazio del transpiler e nel linguaggio principale.

Esempi

1. Nessun utilizzo al di fuori del blocco che racchiude il più vicino: questo blocco di codice genererà un errore di riferimento perché il secondo utilizzo di si xverifica al di fuori del blocco in cui è dichiarato con let:

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

Al contrario, lo stesso esempio con le varopere.

2. Nessuna dichiarazione prima dell'uso:
questo blocco di codice genererà un messaggio ReferenceErrorprima che il codice possa essere eseguito perché xviene utilizzato prima che venga dichiarato:

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

Al contrario, lo stesso esempio con varanalisi e corre senza generare eccezioni.

3. Nessuna redeclaration: il codice seguente dimostra che una variabile dichiarata con letnon può essere dichiarata in seguito:

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

4. Globali non collegati a 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. Facile utilizzo con chiusure: le variabili dichiarate con varnon funzionano bene con chiusure all'interno di anelli. Ecco un semplice ciclo che genera la sequenza di valori che la variabile iha in diversi punti nel tempo:

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

In particolare, questo produce:

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

In JavaScript usiamo spesso le variabili in un momento significativamente più tardi rispetto a quando vengono create. Quando lo dimostriamo ritardando l'output con una chiusura passata a setTimeout:

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

... l'uscita rimane invariata fintanto che restiamo let. Al contrario, se avessimo usato var iinvece:

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

... il loop emette inaspettatamente cinque volte "i is 5":

i is 5
i is 5
i is 5
i is 5
i is 5

5
# 5 non è causato da una condizione di gara. Usando varinvece di let, il codice equivale a: var i = 0; while (i < 5) { doSomethingLater(); i++; } iè esterno alla chiusura e, al momento doSomethingLater()dell'esecuzione, iè già stato incrementato 5 volte, quindi l'output è i is 5cinque volte. Usando let, la variabile si itrova all'interno della chiusura, quindi ogni chiamata asincrona ottiene la propria copia ianziché utilizzare quella "globale" con cui è stata creata var.
Daniel T.

@DanielT .: Non credo che la trasformazione del sollevamento della definizione della variabile dall'inizializzatore del loop spieghi qualcosa. Questa è semplicemente la normale definizione della semantica di for. Una trasformazione più accurata, sebbene più complicata, è la classica for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i is $ {j} ), 125/*ms*/); })(i); }che introduce un "record di attivazione della funzione" per salvare ogni valore icon il nome jall'interno della funzione.
mormegil,

14

Possano le seguenti due funzioni mostrare la differenza:

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
}

13

let è interessante perché ci consente di fare qualcosa del genere:

(() => {
    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++);
            }
        }
    }
})();

Che risulta nel conteggio [0, 7].

Mentre

(() => {
    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++);
            }
        }
    }
})();

Conta solo [0, 1].


2
questa è la prima volta che vedo qualcuno comportarsi come l'ombreggiatura variabile era desiderabile. no, lo scopo di let non è quello di abilitare l'ombreggiatura
John Haugeland,

1
scopo? è un costrutto, puoi usarlo come preferisci, uno dei modi interessanti è come questo.
Dmitry

13

Funzione ambito blocco VS:

La differenza principale tra vare letè che le variabili dichiarate con varsono nell'ambito della funzione . Considerando che le funzioni dichiarate con letsono nell'ambito del blocco . Per esempio:

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 

variabili con var:

Quando la prima funzione testVarviene chiamata la variabile foo, dichiarata con var, è ancora accessibile al di fuori ifdell'istruzione. Questa variabile foosarebbe disponibile ovunque nell'ambito della testVar funzione .

variabili con let:

Quando la seconda funzione testLetviene chiamata la barra delle variabili, dichiarata con let, è accessibile solo all'interno ifdell'istruzione. Poiché le variabili dichiarate con letvengono blocco ambito (in cui un blocco è il codice tra parentesi graffe ad esempio if{}, for{}, function{}).

let le variabili non vengono sollevate:

Un'altra differenza tra vare letè che le variabili dichiarate con let non vengono sollevate . Un esempio è il modo migliore per illustrare questo comportamento:

le variabili con let non vengono sollevate:

console.log(letVar);

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

variabili con var do get issato:

console.log(varVar);

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

Global letnon si affeziona a window:

Una variabile dichiarata con letnell'ambito globale (che è codice che non è in una funzione) non viene aggiunta come proprietà windowsull'oggetto globale . Ad esempio (questo codice è nell'ambito globale):

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


Quando dovrebbe letessere usato var?

Utilizzare letpiù di varogni volta che è possibile perché è semplicemente limitato l'ambito più specifico. Ciò riduce i potenziali conflitti di denominazione che possono verificarsi quando si ha a che fare con un gran numero di variabili. varpuò essere utilizzato quando si desidera che una variabile globale si trovi esplicitamente windowsull'oggetto (considerare sempre attentamente se ciò è veramente necessario).


9

Sembra anche che, almeno in Visual Studio 2015, TypeScript 1.5, "var" consenta dichiarazioni multiple con lo stesso nome di variabile in un blocco e "let" no.

Questo non genererà un errore di compilazione:

var x = 1;
var x = 2;

Questo sarà:

let x = 1;
let x = 2;

9

var è una variabile di portata globale (che può essere sollevata).

leted constè un ambito di blocco.

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


8

Quando si usa let

La letparola chiave associa la dichiarazione di variabile all'ambito di qualsiasi blocco (comunemente una { .. }coppia) in cui è contenuta. In altre parole, letdirige implicitamente l'ambito di qualsiasi blocco per la sua dichiarazione di variabile.

letnon è possibile accedere alle variabili windownell'oggetto perché non è possibile accedervi a livello globale.

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

Quando si usa var

var e le variabili in ES5 hanno scopi nelle funzioni, il che significa che le variabili sono valide all'interno della funzione e non al di fuori della funzione stessa.

varè possibile accedere alle variabili windownell'oggetto perché non è possibile accedervi a livello globale.

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

Se vuoi saperne di più continua a leggere qui sotto

una delle domande di intervista più famose sull'ambito può anche bastare all'uso esatto lete varcome di seguito;

Quando si usa let

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

Questo perché quando si utilizza let, per ogni iterazione di loop la variabile ha un ambito e ha una propria copia.

Quando si usa var

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

Questo perché quando si utilizza var, per ogni iterazione di loop la variabile ha un ambito e ha una copia condivisa.


8

Nella maggior parte dei termini di base,

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

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

⚡️ Sandbox per giocare ↓

Modifica let vs var


7

Se ho letto bene le specifiche, per let fortuna posso anche essere sfruttato per evitare le funzioni di auto-invocazione utilizzate per simulare membri solo privati ​​- un modello di progettazione popolare che riduce la leggibilità del codice, complica il debug, che non aggiunge protezione del codice reale o altri vantaggi - tranne forse per soddisfare qualcuno desiderio di semantica, quindi smetti di usarlo. / 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

Vedi " Emulazione di interfacce private "


Potete approfondire come le espressioni di funzione invocate immediatamente non forniscono "protezione del codice" e letcosa fanno? (Suppongo che intendi IIFE con "funzione auto-invocante".)
Robert Siemer il

E perché ti metti hiddenPropertynel costruttore? Ce n'è solo uno hiddenPropertyper tutte le istanze nella tua "classe".
Robert Siemer,

4

Alcuni hack con 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 e setter con 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)

per favore cosa significa let { type, name, value } = node;? crei un nuovo oggetto con 3 proprietà tipo / nome / valore e inizializzalo con i valori delle proprietà dal nodo?
AlainIb

Nell'esempio 3 stai dichiarando nuovamente il nodo che causa un'eccezione. Anche tutti questi esempi funzionano perfettamente con var.
Rehan Haider,

4

let vs var. Si tratta di portata .

Le variabili var sono globali e sono accessibili praticamente ovunque, mentre lascia che le variabili non siano globali e esistano solo fino a quando una parentesi chiusa le uccide.

Vedi il mio esempio di seguito e nota come la variabile lion (let) agisce diversamente nei due console.logs; diventa fuori campo nel 2 ° console.log.

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.

4

ES6 ha introdotto due nuove parole chiave ( let e const ) alternate a var .

Quando hai bisogno di una decelerazione a livello di blocco puoi scegliere let e const invece di var.

La tabella seguente riassume la differenza tra var, let e const

inserisci qui la descrizione dell'immagine


3

let è una parte di es6. Queste funzioni spiegheranno la differenza in modo semplice.

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
}

3

Quanto segue mostra come 'let' e 'var' sono diversi nell'ambito:

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

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

Il gfoo, definito letinizialmente è nell'ambito globale , e quando lo dichiariamo di gfoonuovo all'interno del if clausesuo ambito è cambiato e quando un nuovo valore è assegnato alla variabile all'interno di quell'ambito, ciò non influisce sull'ambito globale.

Considerando che inizialmente è hfoodefinito nell'ambito globale , ma di nuovo quando lo dichiariamo all'interno dell'ambito, considera l'ambito globale hfoo, sebbene var sia stato nuovamente utilizzato per dichiararlo. E quando riassegniamo il suo valore, vediamo che anche l'hfoo di portata globale è interessato. Questa è la differenza principale.varif clause


2

Come menzionato sopra:

La differenza sta nel scoping. varè impostato sul blocco funzione più vicino ed letè impostato sul blocco allegato più vicino , che può essere più piccolo di un blocco funzione. Entrambi sono globali se al di fuori di qualsiasi blocco. Vediamo un esempio:

Esempio 1:

In entrambi i miei esempi ho una funzione myfunc. myfunccontiene una variabile myvaruguale a 10. Nel mio primo esempio controllo se è myvaruguale a 10 ( myvar==10). Se sì, dichiaro una variabile myvar(ora ho due variabili myvar) usando la varparola chiave e assegnandole un nuovo valore (20). Nella riga successiva stampo il suo valore sulla mia console. Dopo il blocco condizionale, stampa nuovamente il valore di myvarsulla mia console. Se si guarda all'output di myfunc, il myvarvalore è uguale a 20.

lascia la parola chiave

Esempio 2: Nel mio secondo esempio invece di usare la varparola chiave nel mio blocco condizionale dichiaro di myvarusare la letparola chiave. Ora quando chiamo myfunc ottengo due diversi output: myvar=20e myvar=10.

Quindi la differenza è molto semplice, cioè il suo scopo.


3
Si prega di non pubblicare immagini di codice, è considerato una cattiva pratica su SO in quanto non sarà ricercabile per gli utenti futuri (così come i problemi di accessibilità). Inoltre, questa risposta non aggiunge nulla che altre risposte non abbiano già affrontato.
Inostia,

2

Voglio collegare queste parole chiave al contesto di esecuzione, perché il contesto di esecuzione è importante in tutto questo. Il contesto di esecuzione ha due fasi: una fase di creazione e una fase di esecuzione. Inoltre, ogni contesto di esecuzione ha un ambiente variabile e un ambiente esterno (il suo ambiente lessicale).

Durante la fase di creazione di un contesto di esecuzione, var, let e const memorizzeranno comunque la propria variabile in memoria con un valore indefinito nell'ambiente di variabili del contesto di esecuzione specificato. La differenza sta nella fase di esecuzione. Se si utilizza il riferimento a una variabile definita con var prima che gli venga assegnato un valore, non sarà definito. Non verrà sollevata alcuna eccezione.

Tuttavia, non è possibile fare riferimento alla variabile dichiarata con let o const fino a quando non viene dichiarata. Se si tenta di utilizzarlo prima che venga dichiarato, verrà sollevata un'eccezione durante la fase di esecuzione del contesto di esecuzione. Ora la variabile sarà ancora in memoria, per gentile concessione della fase di creazione del contesto di esecuzione, ma il motore non ti consentirà di utilizzarla:

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

Con una variabile definita con var, se il motore non riesce a trovare la variabile nell'ambiente variabile del contesto di esecuzione corrente, salirà la catena dell'ambito (l'ambiente esterno) e controllerà l'ambiente variabile dell'ambiente esterno per la variabile. Se non lo trova lì, continuerà a cercare nella Scope Chain. Questo non è il caso di let e const.

La seconda caratteristica di let è che introduce l'ambito del blocco. I blocchi sono definiti da parentesi graffe. Gli esempi includono blocchi funzione, se blocchi, per blocchi, ecc. Quando si dichiara una variabile con let inside di un blocco, la variabile è disponibile solo all'interno del blocco. In effetti, ogni volta che viene eseguito il blocco, ad esempio all'interno di un ciclo for, verrà creata una nuova variabile in memoria.

ES6 introduce anche la parola chiave const per dichiarare le variabili. const è anche con ambito di blocco. La differenza tra let e const è che le variabili const devono essere dichiarate usando un inizializzatore, altrimenti genererà un errore.

E, infine, quando si tratta del contesto di esecuzione, le variabili definite con var verranno associate all'oggetto 'this'. Nel contesto di esecuzione globale, quello sarà l'oggetto finestra nei browser. Questo non è il caso di let o const.


2

Penso che i termini e la maggior parte degli esempi siano un po 'schiaccianti. Il problema principale che ho avuto personalmente con la differenza è capire che cos'è un "Blocco". A un certo punto mi sono reso conto che un blocco sarebbe qualsiasi parentesi graffa ad eccezione IFdell'istruzione. una parentesi {di apertura di una funzione o di un loop definirà un nuovo blocco, qualsiasi cosa definita al letsuo interno, non sarà disponibile dopo la parentesi }di chiusura della stessa cosa (funzione o loop); Con questo in mente, era più facile capire:

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);


1

Ora penso che ci sia un ambito migliore delle variabili in un blocco di istruzioni usando 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
}

Penso che le persone inizieranno a usare let qui dopo in modo che abbiano un ambito simile in JavaScript come altre lingue, Java, C #, ecc.

Le persone che non avevano una chiara comprensione dello scoping in JavaScript erano solite fare l'errore in precedenza.

Il sollevamento non è supportato tramite let.

Con questo approccio vengono rimossi gli errori presenti in JavaScript.

Fare riferimento a ES6 Approfondimento: let e const per capirlo meglio.


Per una comprensione approfondita su di esso consultare il link - davidwalsh.name/for-and-against-let
swaraj patil

1

Questo articolo definisce chiaramente la differenza tra var, let e const

const è un segnale che l'identificatore non verrà riassegnato.

let, è un segnale che la variabile può essere riassegnata, ad esempio un contatore in un ciclo o uno scambio di valore in un algoritmo. Segnala inoltre che la variabile verrà utilizzata solo nel blocco in cui è definita, che non è sempre l'intera funzione di contenimento.

varè ora il segnale più debole disponibile quando si definisce una variabile in JavaScript. La variabile può o non può essere riassegnata e la variabile può o non può essere utilizzata per un'intera funzione, o solo allo scopo di un blocco o loop.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.