Qual è la differenza tra l'uso di "let" e "var"?
-
11-09-2019 - |
Domanda
Introduzione di ECMAScript 6 IL let
dichiarazione.
Ho sentito dire che è descritta come una variabile "locale", ma non sono ancora del tutto sicuro di come si comporti diversamente rispetto a var
parola chiave.
Quali sono le differenze?Quando dovrebbe let
essere utilizzato var
?
Soluzione
di ambito
La differenza principale è scoping regole. Le variabili dichiarate da var
parola ha come ambito corpo funzione immediata (da qui la funzione portata) mentre le variabili let
vengono ambiti all'immediata racchiude blocco indicato con { }
(quindi, la portata di 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 parola chiave let
è stato introdotto per la lingua era portata funzione è confusa e fu uno dei principale fonte di bug in javascript.
Date un'occhiata a questo esempio da un'altra domanda 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
era uscita di consolare ogni volta funcs[j]();
è stata invocata in quanto funzioni anonime erano legati alla stessa stessa variabile.
La gente doveva creare creare funzioni immediatamente invocate per catturare valore corretto dai loop ma che era anche peloso.
Sollevamento
Mentre variabili dichiarate con var
parola chiave sono "sollevati" per la parte superiore del blocco che significa che sono accessibili nella loro portata che racchiude anche prima che siano dichiarati:
function run() {
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
}
run();
lasciare che le variabili non sono inizializzate finché non viene valutata la loro definizione. accedervi prima che i risultati di inizializzazione in un ReferenceError
. Variabile detto di essere in "zona morta temporale" dall'inizio del blocco finché l'inizializzazione viene elaborato.
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();
La creazione di proprietà oggetto globale
Al livello superiore, let
, a differenza 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, var
vi permetterà di ri-dichiara la stessa variabile nello stesso ambito, mentre let
solleva uno 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
Altri suggerimenti
let
può essere utilizzato anche per evitare problemi con le chiusure. Si lega il valore fresco, piuttosto che mantenere un vecchio di riferimento, come illustrato negli esempi che seguono.
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>
<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>
Codice di cui sopra dimostra un classico problema JavaScript chiusura. Riferimento alla variabile i
viene memorizzato nella chiusura a scatto gestore, piuttosto che il valore effettivo della i
.
Ogni singolo gestore clic si riferiscono allo stesso oggetto, perché c'è un solo oggetto contatore che tiene 6 in modo da ottenere sei per ogni clic.
Una soluzione generale è quello di avvolgere questo in una funzione anonima e passare i
come argomento. Tali problemi possono essere evitati ora utilizzando let
invece var
come mostrato nel seguente codice.
(Testato in 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>
<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>
Qual è la differenza tra let
e var
?
- Una variabile definita utilizzando un'istruzione
var
è conosciuta in tutto la funzione è definito nella, fin dall'inizio della funzione. * - Una variabile definita utilizzando un'istruzione
let
è noto solo in < strong> blocco è definita, dal momento in cui viene definito in avanti. **
Per capire la differenza, si consideri 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 j
variabile è conosciuta solo nel primo ciclo for, ma non prima e dopo. Eppure, il nostro i
variabile è conosciuto in tutta la funzionalità.
Inoltre, si consideri che le variabili di blocco ambito non sono noti prima di essere dichiarate, perché non sono issate. Non sei anche permesso di ridichiarare stesso blocco ambito variabile all'interno dello stesso blocco. Questo rende blocco variabili con scope meno soggetta ad errori di variabili ambito globale o funzionalmente, che vengono issati e che non producono errori nel caso di dichiarazioni multiple.
E 'sicuro da usare let
oggi?
Alcune persone sostengono che in futuro avremo SOLO utilizziamo lasciare dichiarazioni e che le dichiarazioni var diventerà obsoleto. JavaScript guru Kyle Simpson ha scritto un articolo molto elaborato sul perché egli ritiene che non sarà il caso .
Oggi, tuttavia, che non è sicuramente il caso. In realtà, abbiamo bisogno in realtà chiederci se è sicuro di utilizzare l'istruzione let
. La risposta a questa domanda dipende dall'ambiente:
-
Se si scrive sul lato server codice JavaScript ( Node.js ), si può tranquillamente utilizzare l'istruzione
let
. -
Se si scrive JavaScript lato client codice e utilizzare un transpiler basato su browser (come < strong> Traceur o href="https://github.com/babel/babel-standalone" rel="noreferrer"> babel-alone ), si può tranquillamente utilizzare l'istruzione
let
, tuttavia il codice è probabile che sia tutt'altro che ottimale rispetto alle prestazioni. -
Se si scrive JavaScript lato client il codice e utilizzare un transpiler base Node (come il traceur script di shell o href="https://babeljs.io/" rel="noreferrer"> Babel ), si può tranquillamente utilizzare l'istruzione
let
. E perché il browser verrà a conoscenza del codice transpiled, svantaggi prestazioni dovrebbero essere limitate. -
Se si scrive sul lato client il codice JavaScript e non utilizzare un transpiler, è necessario considerare il supporto del browser.
Ci sono ancora alcuni browser che non supportano
let
a tutti:
Come tenere traccia di supporto del browser
Per una panoramica up-to-date, di cui i browser supportano la dichiarazione let
al momento della vostra lettura questa risposta, vedere questa pagina Can I Use
.
* va a livello globale e funzionalmente ambitoVARIABILI possono essere inizializzati e utilizzati prima di essere dichiarati perché le variabili JavaScript sono issato . Questo significa che le dichiarazioni sono sempre molto per la parte superiore del campo di applicazione.
** Blocca ambito variabili non vengono issate
Ecco un del let
parola chiave con alcuni esempi.
let
funziona comevar
. La differenza principale è che la portata di una variabilevar
rappresenta l'intera funzione racchiude
Questo tavolo su Wikipedia indica che i browser supporta Javascript 1.7.
Si noti che solo i browser Mozilla e Chrome lo supportano. IE, Safari, e potenzialmente altri no.
La risposta accettata manca un punto:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
let
Blocca l'ambito
Variabili dichiarate utilizzando il file let
hanno un ambito di blocco, il che significa che sono disponibili solo in bloccare in cui sono stati dichiarati.
Al livello più alto (all'esterno di una funzione)
Al livello più alto, le variabili dichiarate utilizzando let
non creare 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 all'esterno di un blocco), let
ha 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 isolato
Variabili dichiarate utilizzando let
all'interno di un blocco non è possibile accedere all'esterno 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
Variabili dichiarate con let
in loop è possibile fare riferimento 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 usi let
invece di var
in un ciclo, ad ogni iterazione ottieni una nuova variabile.Ciò significa che puoi tranquillamente utilizzare una chiusura all'interno di un ciclo.
// 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
Per colpa di la zona morta temporale, variabili dichiarate utilizzando let
non è possibile accedervi prima che vengano dichiarati.Il tentativo 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 è possibile dichiarare la stessa variabile più volte utilizzando let
.Inoltre, non puoi dichiarare una variabile usando let
con lo stesso identificatore 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
- ha un ambito di blocco e ha TDZ.Ci sono però due cose diverse.
Nessuna riassegnazione
Variabile dichiarata utilizzando const
non può essere riassegnato.
const a = 42;
a = 43; // TypeError: Assignment to constant variable.
Tieni presente 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()
.
L'inizializzatore è obbligatorio
È sempre necessario specificare un valore quando si dichiara una variabile utilizzando const
.
const a; // SyntaxError: Missing initializer in const declaration
Ecco un esempio per la differenza tra i due (supporto appena iniziato per Chrome):
Come si può vedere la variabile var j
continua ad avere un valore al di fuori del campo di applicazione per il ciclo (Block Ambito di applicazione), ma la variabile let i
non è definito al di fuori del campo di applicazione per il ciclo.
"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);
Ci sono alcune differenze sottili - let
scoping si comporta più come scoping variabile fa in più o meno qualsiasi altra lingua.
es. E 'ambiti al blocco racchiude, Essi non esistono prima di essere dichiarate, ecc.
Tuttavia vale la pena notare che let
è solo una parte del più recenti implementazioni Javascript e ha diversi gradi di .
-
variabile non Sollevamentolet
sarà non issare per l'intero ambito del blocco sono visualizzati. Per contro,var
potrebbe 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
var
elet
vengono issate . -
Garbage Collection
ambito blocco di
let
è utile riferisce a chiusure e garbage collection per recuperare la memoria. Si consideri,function process(data) { //... } var hugeData = { .. }; process(hugeData); var btn = document.getElementById("mybutton"); btn.addEventListener( "click", function click(evt){ //.... });
Il callback gestore
click
non ha bisogno della variabilehugeData
a tutti. Teoricamente, dopo corseprocess(..)
, l'enorme struttura di datihugeData
potrebbe essere garbage collection. Tuttavia, è possibile che qualche motore JS dovrà comunque mantenere questa enorme struttura, dal momento che la funzioneclick
ha una chiusura sopra l'intero ambito.Tuttavia, la portata di blocco può fare questo enorme struttura dati a 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){ //.... });
-
loop
let
let
nel loop può ri-associa per ciascuna iterazione del ciclo, avendo cura di ri-assegnare il valore dalla fine del precedente iterazione del ciclo. Si consideri,// print '5' 5 times for (var i = 0; i < 5; ++i) { setTimeout(function () { console.log(i); }, 1000); }
Tuttavia, sostituire
var
conlet
// print 1, 2, 3, 4, 5. now for (let i = 0; i < 5; ++i) { setTimeout(function () { console.log(i); }, 1000); }
Poiché
let
creare un nuovo ambiente lessicale con i nomi di a) l'espressione initialiser b) ciascuna iterazione (previosly per valutare l'espressione di incremento), maggiori dettagli sono qui .
La differenza principale è la scopo differenza, mentre permettere può essere disponibile solo all'interno del scopo è dichiarato, come nel ciclo for, var è possibile accedere all'esterno del loop, ad esempio.Dalla documentazione in MDN (esempi anche da MDN):
permettere consente di dichiarare variabili con ambito limitato al blocco, all'istruzione o all'espressione in cui viene utilizzato.Questo è diverso da var parola chiave, che definisce una variabile a livello globale o localmente su un'intera funzione indipendentemente dall'ambito del blocco.
Variabili dichiarate da permettere hanno come ambito il blocco in cui sono definiti, nonché gli eventuali sottoblocchi contenuti.In questo modo, permettere funziona in modo molto simile var.La differenza principale è che l'ambito di a var variabile è l'intera funzione di inclusione:
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 più alto di programmi e funzioni, permettere, 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, consente di limitare l'ambito della variabile a quel blocco.Nota la differenza tra var il cui scope è 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 che è la funzionalità ECMA6, quindi non è ancora completamente supportata, quindi è meglio trasporla sempre in ECMA5 usando Babel ecc...per maggiori informazioni sulla visita sito web di Babele
Ecco un esempio da aggiungere a ciò che altri hanno già scritto. Si supponga di voler fare una serie di funzioni, adderFunctions
, dove ogni funzione prende un singolo argomento Numero e restituisce la somma dell'argomento e l'indice della funzione nella matrice. Cercando di generare adderFunctions
con un ciclo utilizzando la parola chiave var
non funziona il modo in cui qualcuno potrebbe ingenuamente aspettare:
// 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 di cui sopra non genera la matrice desiderata di funzioni perché portata di i
estende oltre l'iterazione del blocco for
in cui è stato creato ogni funzione. Invece, alla fine del ciclo, il i
in chiusura di ciascuna funzione si riferisce al valore di i
alla fine del ciclo (1000) per ogni funzione anonima in adderFunctions
. Questo non è quello che volevamo affatto: ora abbiamo una serie di 1000 diverse funzioni in memoria con esattamente lo stesso comportamento. E se successivamente aggiornare il valore della i
, la mutazione interesserà tutto il adderFunctions
.
Tuttavia, siamo in grado di provare di nuovo usando la parola chiave let
:
// 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, è i
rimbalzo su ogni iterazione del ciclo for
. Ogni funzione oggi mantiene il valore della i
al momento della creazione della funzione, e adderFunctions
si comporta come previsto.
Ora, immagine miscelazione dei due comportamenti e probabilmente vedrete il motivo per cui non è consigliabile mescolare la più recente let
e const
con il var
vecchio nello stesso script. In questo modo può provocare è un codice spettacolare confusione.
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 lasciate che questo accada a voi. Utilizzare un Linter.
Nota: Questo è un esempio di insegnamento destinato a dimostrare il comportamento
var
/let
in loop e con chiusure di funzione che sarebbe anche facile da capire. Questo sarebbe un modo terribile per aggiungere i numeri. Ma la tecnica generale di catturare dati in chiusure di funzione anonima potrebbe essere incontrato nel mondo reale in altri contesti. YMMV.
La differenza sta nel scopo delle variabili dichiarate con ciascuno.
In pratica, ci sono una serie di conseguenze utili derivanti dalla differenza di portata:
let
le variabili sono visibili solo nei loro file recinto più vicino blocco ({ ... }
).let
le variabili sono utilizzabili solo nelle righe di codice che si verificano Dopo la variabile è dichiarata (anche se vengono issati!).let
le variabili non possono essere ridichiarate da una variabile successivavar
Olet
.- Globale
let
le variabili non vengono aggiunte al globalewindow
oggetto. let
le variabili sono facile da usare con chiusure (non causano condizioni di gara).
Le restrizioni imposte dall let
ridurre la visibilità delle variabili e aumentare la probabilità che vengano rilevate tempestivamente collisioni di nomi inaspettate.Ciò rende più semplice tenere traccia e ragionare sulle variabili, comprese le loro raggiungibilità(aiutando a recuperare la memoria inutilizzata).
Di conseguenza, let
è meno probabile che le variabili causino problemi se utilizzate in programmi di grandi dimensioni o quando framework sviluppati in modo indipendente vengono combinati in modi nuovi e inaspettati.
var
può ancora essere utile se sei sicuro di volere l'effetto di associazione singola quando usi una chiusura in un ciclo (#5) o per dichiarare variabili globali visibili esternamente nel tuo codice (#4).Utilizzo di var
per le esportazioni possono essere sostituiti se export
migra dallo spazio del transpiler al linguaggio principale.
Esempi
1.Nessun utilizzo al di fuori del blocco di recinzione più vicino:Questo blocco di codice genererà un errore di riferimento a causa del secondo utilizzo di x
si verifica all'esterno del blocco con cui è dichiarato let
:
{
let x = 1;
}
console.log(`x is ${x}`); // ReferenceError during parsing: "x is not defined".
Al contrario, lo stesso esempio con var
lavori.
2.Nessun utilizzo prima della dichiarazione:
Questo blocco di codice genererà un file ReferenceError
prima che il codice possa essere eseguito perché x
viene utilizzato prima di essere 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 var
analizza ed esegue senza generare eccezioni.
3.Nessuna nuova dichiarazione:Il codice seguente dimostra che una variabile dichiarata con let
non possono essere ridichiarati successivamente:
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:Variabili dichiarate con var
non funzionano bene con le chiusure all'interno dei loop.Ecco un semplice ciclo che restituisce la sequenza di valori della variabile i
ha in diversi momenti:
for (let i = 0; i < 5; i++) {
console.log(`i is ${i}`), 125/*ms*/);
}
Nello specifico, questo restituisce:
i is 0
i is 1
i is 2
i is 3
i is 4
In JavaScript spesso utilizziamo le variabili in un momento significativamente successivo 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'output rimane invariato finché rimaniamo fedeli let
.Al contrario, se avessimo usato var i
Invece:
for (var i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
...il ciclo restituisce inaspettatamente "i is 5" cinque volte:
i is 5
i is 5
i is 5
i is 5
i is 5
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
}
let
è interessante, perché ci permette di fare qualcosa di simile a questo:
(() => {
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++);
}
}
}
})();
Il che si traduce in conteggio [0, 7].
considerando che
(() => {
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++);
}
}
}
})();
Solo conta [0, 1].
Funzione VS portata blocco:
La differenza principale tra var
e let
è che le variabili dichiarate con var
sono Funzione ambito . Mentre le funzioni dichiarate con let
sono blocco ambito . Ad 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 testVar
viene chiamata variabile foo, dichiarata con var
, è ancora accessibile al di fuori della dichiarazione if
. Questo foo
variabile sarà disponibile in tutto il mondo nel campo di applicazione del testVar
Funzione .
variabili con let
:
Quando la seconda funzione testLet
viene chiamata la barra variabile dichiarata con let
, è accessibile solo all'interno della dichiarazione if
. Perché le variabili dichiarate con let
sono blocco ambito (in cui un blocco è il codice tra parentesi graffe per esempio if{}
, for{}
, function{}
).
variabili let
non vengono issate:
Un'altra differenza tra var
e let
è variabili con dichiarata con let
non si ottiene issato . Un esempio è il modo migliore per illustrare questo comportamento:
variabili con let
non vengono issati:
console.log(letVar);
let letVar = 10;
// referenceError, the variable doesn't get hoisted
variabili con var
do issato:
console.log(varVar);
var varVar = 10;
// logs undefined, the variable gets hoisted
let
globale non viene attaccato al window
:
Una variabile dichiarata con let
nell'ambito globale (che è il codice che non è in funzione) non ottiene aggiunto come una proprietà sull'oggetto window
globale. Per esempio (questo codice è di portata 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 essere utilizzato più
let
var
?
Usa let
oltre var
ogni volta che è possibile, perché è semplicemente ambito più specifico. Questo riduce i potenziali conflitti di nomi che possono verificarsi quando si tratta di un gran numero di variabili. var
può essere utilizzato quando si desidera una variabile globale in modo esplicito di essere l'oggetto window
(sempre considerare attentamente se questo è davvero necessario).
Risulta inoltre che, almeno in Visual Studio 2015, dattiloscritto 1.5, "var" consente a più dichiarazioni dello stesso nome di variabile in un blocco, e "lasciare che" non lo fa.
Questa non genererà un errore di compilazione:
var x = 1;
var x = 2;
Questa volontà:
let x = 1;
let x = 2;
var
è portata variabile globale (paranco-in grado).
let
e const
è bloccare portata.
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
quando si utilizza let
La parola chiave let
attribuisce la dichiarazione di variabile per la portata di qualsiasi blocco (comunemente un paio { .. }
) è contenuta in. In altre parole, let
dirotta implicitamente portata di qualsiasi blocco per la sua dichiarazione delle variabili.
variabili let
non è possibile accedere nell'oggetto window
perché non possono accedere globalmente.
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 utilizza var
var
e le variabili in ES5 ha portate nelle funzioni che significano le variabili sono valide all'interno della funzione e non al di fuori della funzione stessa.
variabili var
possibile accedere nell'oggetto window
perché non possono accedere globalmente.
function a(){ // this is the Max Scope for var variable
{
var x = 12;
}
console.log(x);
}
a(); // 12
Se volete saperne di più continua a leggere qui di seguito
una delle più famose domande di intervista sulla portata anche può bastare il corretto utilizzo di let
e var
come sotto;
Quando si utilizza 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 del ciclo la variabile è ambito e ha la sua copia.
Quando si utilizza 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 del ciclo la variabile è ambito e ha condiviso la copia.
Se leggo bene le specifiche in quel momento let
per fortuna può anche essere sfruttato per evitare funzioni di autoinvocazione utilizzato per simulare solo membri privati - un modello di progettazione popolare che riduce la leggibilità del codice, complica il debug, che non aggiunge alcuna protezione reale del codice o altri vantaggi, tranne forse soddisfare il desiderio di semantica di qualcuno, quindi smetti di usarlo./scatenarsi
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
Vedere 'Emulazione di interfacce private'
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)
let vs var.È tutta una questione di scopo.
le variabili var sono globali ed è accessibile praticamente ovunque, mentre lascia che le variabili non siano globali ed esistono solo finché una parentesi di chiusura non li uccide.
Guarda il mio esempio qui sotto e nota come la variabile lion (let) agisce diversamente nei due console.logs;diventa fuori ambito 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.
let è una parte di ES6. Queste funzioni spiegare 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
}
In precedenza c'erano solo due ambiti in JavaScript, vale a dire funzionali e globali. Con la parola chiave 'let
' JavaScript ha introdotto variabili block-level
.
Per avere una completa comprensione del 'lasciare' parola chiave, ES6: ‘lasciare’ parola chiave per dichiarare variabili in JavaScript vi aiuterà
. Ora penso che ci sia una migliore scoping di variabili da un blocco di istruzioni che utilizzano 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
}
Credo che le persone inizieranno a utilizzare lasciare qui dopo in modo che essi avranno scoping simile in JavaScript, come altre lingue, Java, C #, ecc.
Le persone con non una chiara comprensione di scoping in JavaScript utilizzati per fare l'errore precedente.
sollevamento non è supportata utilizzando let
.
Con questo approccio gli errori presenti in JavaScript sono sempre rimossi.
Fare riferimento a ES6 Approfondimenti :. lasciò e const per capire meglio
Questo articolo definisce chiaramente la differenza tra var, lasciare e const
const
è un segnale che l'identificatore non verrà riassegnato.
let
, è un segnale che la variabile venga rimessa, quale un contatore in un loop, o uno scambio valore in un algoritmo. Segnala inoltre che la variabile sarà usato solo nel blocco è definito, 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 riassegnato, e variabile può o non può essere utilizzato per una funzione intera, o solo per lo scopo di un blocco o ad anello.
https: // media. com / javascript-scena / javascript-ES6-var-let-o-const-ba58b8dcde75 # .esmkpbg9b
Come accennato in precedenza:
La differenza è dell'ambito.
var
è ambito per il funzione più vicino blocco elet
ambito la blocco racchiude vicina , che può essere più piccolo di un blocco funzionale. Entrambi sono globali se al di fuori qualsiasi block.Lets vedere un esempio:
Esempio 1:
Nel mio entrambi gli esempi Ho una funzione myfunc
. myfunc
contiene una myvar
variabile è uguale a 10.
Nel mio primo esempio a verificare se myvar
uguale a 10 (myvar==10
). Se sì, mi dichiaro agian un myvar
variabile (ora ho due variabili myvar) utilizzando var
parola chiave e assegnarle un nuovo valore (20). Nella riga successiva si stampa il suo valore sulla mia console. Dopo il blocco condizionale ho di nuovo stampare il valore di myvar
sulla mia console. Se si guarda l'output di myfunc
, myvar
ha un valore uguale a 20.
Esempio 2:
Nel mio secondo esempio invece di utilizzare var
parola chiave nel mio blocco condizionale dichiaro myvar
usando let
parola chiave. Ora, quando chiamo myfunc
ottengo due uscite diverse: myvar=20
e myvar=10
Quindi, la differenza è molto semplice cioè la sua portata.
Date un'occhiata a questa immagine, ho creato un esempio molto semplice per la dimostrazione delle variabili const
e let
. Come si può vedere, quando si tenta di modificare variabile const
, si otterrà l'errore ( Il tentativo di sostituire 'nome', che è costante '), ma dare un'occhiata a variabile let
...
Per prima cosa dichiariamo let age = 33
, e successivamente assegniamo qualche altro age = 34;
valore, che è ok, noi non hanno eventuali errori quando si tenta di cambiare let
variabile
Credo che i termini e la maggior parte degli esempi sono un po 'opprimente,
Il problema principale che ho avuto personalmente con la differenza è capire cosa sia un "blocco" è.
Ad un certo punto mi sono reso conto, un blocco sarebbe alcun parentesi graffe ad eccezione di dichiarazione IF
.
un {
parentesi di apertura di una funzione o loop definire un nuovo blocco, nulla definita con let
all'interno di esso, non sarà disponibile dopo il }
parentesi di chiusura della stessa cosa (funzione o loop);
Con questo in mente, era più facile da 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);
Poiché attualmente sto cercando di comprendere a fondo JavaScript, condividerò la mia breve ricerca che contiene alcuni degli ottimi pezzi già discussi più alcuni altri dettagli in una prospettiva diversa.
Comprendere la differenza tra var E permettere può essere più semplice se comprendiamo la differenza tra funzione E ambito del blocco.
Consideriamo i seguenti casi:
(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]
Quando timer()
viene chiamato an Contesto di esecuzione viene creato che conterrà sia il file Ambiente variabile e tutto il Ambienti lessicali corrispondente ad ogni iterazione.
E un esempio più semplice
Ambito della funzione
function test() {
for(var z = 0; z < 69; z++) {
//todo
}
//z is visible outside the loop
}
Ambito di blocco
function test() {
for(let z = 0; z < 69; z++) {
//todo
}
//z is not defined :(
}
Voglio collegare queste parole chiave per il contesto di esecuzione, perché il contesto di esecuzione è importante in tutto questo. Il contesto di esecuzione ha due fasi: una fase di creazione e di fase di esecuzione. Inoltre, ogni contesto di esecuzione è una variabile di ambiente ed esterno Ambiente (il suo lessicale Ambiente).
Durante la fase di creazione di un contesto di esecuzione, var, lascia e const sarà ancora conservare la sua variabile nella memoria con un valore non definito nella variabile d'ambiente di un dato contesto di esecuzione. La differenza è nella fase di esecuzione. Se si utilizza una variabile di riferimento definito con var prima che venga assegnato un valore, sarà solo indefinito. Nessuna eccezione sarà sollevata.
Tuttavia, non è possibile fare riferimento alla variabile dichiarata con let o const fino a quando non viene dichiarato. Se si tenta di utilizzarlo prima che venga dichiarata, quindi un'eccezione sarà sollevata 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 permetterà di usarlo:
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 nella variabile d'ambiente del contesto di esecuzione corrente, quindi andrà a monte della catena portata (l'ambiente esterno) e controllare variabile d'ambiente del Outer ambiente per la variabile. Se non riesce a trovare lì, continuerà a cercare la catena Scope. Questo non è il caso di lasciare e const.
La seconda caratteristica di let è introduce ambito blocco. Blocchi sono definiti da parentesi graffe. Esempi includono blocchi funzionali, se i blocchi, per i blocchi, ecc Quando si dichiara una variabile con let all'interno di un blocco, la variabile è disponibile solo all'interno del blocco. Infatti, ogni volta che il blocco viene eseguito, ad esempio all'interno di un ciclo, si creerà una nuova variabile nella memoria.
ES6 introduce anche la parola chiave const per la dichiarazione di variabili. const è anche bloccare ambito. La differenza tra let e const è che le variabili const devono essere dichiarate utilizzando un inizializzatore, oppure genereranno un errore.
E, infine, quando si tratta del contesto di esecuzione, le variabili definite con var saranno allegate al 'questo' oggetto. Nel contesto di esecuzione globale, che sarà l'oggetto window nei browser. Questo non è il caso per let o const.