¿Cuál es la diferencia entre usar "let" y "var"?

4545

Introducción de ECMAScript 6 la letdeclaración .

He oído que se describe como una variable "local", pero todavía no estoy muy seguro de cómo se comporta de manera diferente al var palabra clave.

¿Cuáles son las diferencias? ¿Cuándo se debe letusar var?

TM.
fuente
105
ECMAScript es el estándar y letse incluye en el borrador de la sexta edición y probablemente estará en la especificación final.
Richard Ayotte
55
Consulte kangax.github.io/es5-compat-table/es6 para obtener una matriz de soporte actualizada de las funciones de ES6 (incluido let). Al momento de escribir Firefox, Chrome e IE11 lo admiten (aunque creo que la implementación de FF no es del todo estándar).
Nico Burns
22
Durante mucho tiempo no sabía que los vars en un bucle for tenían un alcance para la función en la que estaba envuelto. Recuerdo haberlo descubierto por primera vez y pensé que era muy estúpido. Veo algo de poder, aunque ahora sé cómo se pueden usar los dos por diferentes razones y cómo, en algunos casos, es posible que desee usar una var en un bucle for y no tener un alcance en el bloque.
Eric Bishard
1
Esta es una muy buena lectura wesbos.com/javascript-scoping
onmyway133
1
Respuesta bien explicada aquí stackoverflow.com/a/43994458/5043867
Pardeep Jain

Respuestas:

6102

Reglas de alcance

La principal diferencia son las reglas de alcance. Las variables declaradas por varpalabra clave tienen un alcance en el cuerpo de la función inmediata (de ahí el alcance de la función) mientras que las letvariables tienen un alcance en el bloque de cierre inmediato denotado por { }(de ahí el alcance del bloque).

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

  console.log(foo, bar);

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

  console.log(baz); // ReferenceError
}

run();

La razón por la cual letse introdujo la palabra clave en el lenguaje fue que el alcance de la función es confuso y fue una de las principales fuentes de errores en JavaScript.

Eche un vistazo a este ejemplo de otra pregunta de 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: 3se emitía a la consola cada vez que funcs[j]();se invocaba ya que las funciones anónimas estaban vinculadas a la misma variable.

La gente tenía que crear funciones invocadas de inmediato para capturar el valor correcto de los bucles, pero eso también era complicado.

Elevación

Si bien las variables declaradas con la varpalabra clave son izadas (inicializadas undefinedantes de que se ejecute el código), lo que significa que son accesibles en su ámbito de inclusión incluso antes de que se declaren:

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

run();

letLas variables no se inicializan hasta que se evalúa su definición. Acceder a ellos antes de que la inicialización resulte en a ReferenceError. Se dice que la variable está en "zona muerta temporal" desde el inicio del bloque hasta que se procesa la inicialización.

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

checkHoisting();

Crear propiedad de objeto global

En el nivel superior let, a diferencia de var, no crea una propiedad en el objeto global:

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

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

Redeclaración

En modo estricto, varle permitirá volver a declarar la misma variable en el mismo ámbito mientras 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
ThinkingStiff
fuente
23
Recuerde que puede crear bloque cuando lo desee. función () {código; {let inBlock = 5; } código; };
promedio Joe
177
Entonces, ¿el propósito de las declaraciones de let solo es liberar memoria cuando no se necesita en un determinado bloque?
NoBugs
219
@NoBugs, sí, y se recomienda que las variables solo existan donde se necesiten.
Batman
67
letla expresión de bloque let (variable declaration) statementno es estándar y se eliminará en el futuro, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus
19
Entonces, no puedo pensar en ningún caso en el que usar var sea de alguna utilidad. ¿Podría alguien darme un ejemplo de una situación en la que es preferible usar var?
Luis Sieira
622

letTambién se puede utilizar para evitar problemas con los cierres. Vincula un valor nuevo en lugar de mantener una referencia antigua como se muestra en los ejemplos a continuación.

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>

El código anterior muestra un problema clásico de cierre de JavaScript. La referencia a la ivariable se almacena en el cierre del controlador de clics, en lugar del valor real de i.

Cada controlador de un solo clic se referirá al mismo objeto porque solo hay un objeto de contador que contiene 6, por lo que obtienes seis en cada clic.

Una solución general es envolver esto en una función anónima y pasarlo icomo argumento. Tales problemas también se pueden evitar ahora utilizando en su letlugar varcomo se muestra en el código a continuación.

(Probado en Chrome y Firefox 50)

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

Gurpreet Singh
fuente
54
Eso es realmente genial. Esperaría que "i" se defina fuera del cuerpo del bucle dentro de los corchetes y NO forme un "cierre" alrededor de "i". Por supuesto, su ejemplo demuestra lo contrario. Creo que es un poco confuso desde el punto de vista de la sintaxis, pero este escenario es tan común que tiene sentido apoyarlo de esa manera. Muchas gracias por mencionar esto.
Karol Kolenda
99
IE 11 es compatible let, pero alerta "6" para todos los botones. ¿Tienes alguna fuente que diga cómo letse supone que debe comportarse?
Jim Hunziker
10
Parece que su respuesta es el comportamiento correcto: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker
11
De hecho, este es un error común en Javascript y ahora puedo ver por qué letsería realmente útil. La configuración de escuchas de eventos en un bucle ya no requiere una expresión de función invocada inmediatamente para el alcance local ien cada iteración.
Adrian Moisa
19
El uso de "let" simplemente retrasa este problema. Por lo tanto, cada iteración crea un ámbito de bloque privado independiente, pero la variable "i" todavía puede corromperse por los cambios posteriores dentro del bloque, (dado que la variable iteradora generalmente no se cambia dentro del bloque, pero otras variables let declaradas dentro del bloque bien pueden be) y cualquier función declarada en el bloque de lata, cuando se invoca, corromper el valor de "i" para otras funciones declarado dentro del bloque, ya que hacen comparten el mismo ámbito de bloque privado, por tanto, la misma referencia a "i".
Gary
199

¿Cuál es la diferencia entre lety var?

  • Una variable definida usando una vardeclaración se conoce en toda la función en la que se define, desde el inicio de la función. (*)
  • Una variable definida usando una letdeclaración solo se conoce en el bloque en el que se define, desde el momento en que se define en adelante. (**)

Para comprender la diferencia, considere el siguiente código:

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

Aquí, podemos ver que nuestra variable jsolo se conoce en el primer bucle for, pero no antes y después. Sin embargo, nuestra variable ies conocida en toda la función.

Además, tenga en cuenta que las variables de ámbito de bloque no se conocen antes de declararse porque no se izan. Tampoco se le permite volver a declarar la misma variable de ámbito de bloque dentro del mismo bloque. Esto hace que las variables de ámbito de bloque sean menos propensas a errores que las variables de ámbito global o funcional, que se izan y que no producen ningún error en caso de declaraciones múltiples.


¿Es seguro usarlo lethoy?

Algunas personas argumentan que en el futuro SOLO usaremos declaraciones let y que las declaraciones var se volverán obsoletas. El gurú de JavaScript Kyle Simpson escribió un artículo muy elaborado sobre por qué cree que ese no será el caso .

Hoy, sin embargo, ese definitivamente no es el caso. De hecho, debemos preguntarnos si es seguro usar la letdeclaración. La respuesta a esa pregunta depende de su entorno:

  • Si está escribiendo código JavaScript del lado del servidor ( Node.js ), puede usar la letdeclaración de forma segura .

  • Si está escribiendo código JavaScript del lado del cliente y usa un transpilador basado en navegador (como Traceur o babel-standalone ), puede usar la letdeclaración de forma segura , sin embargo, es probable que su código sea todo menos óptimo con respecto al rendimiento.

  • Si está escribiendo código JavaScript del lado del cliente y usa un transpilador basado en Nodo (como el script de shell traceur o Babel ), puede usar la letdeclaración de manera segura . Y debido a que su navegador solo sabrá sobre el código transpilado, los inconvenientes de rendimiento deben ser limitados.

  • Si está escribiendo código JavaScript del lado del cliente y no usa un transpilador, debe considerar la compatibilidad con el navegador.

    Todavía hay algunos navegadores que no admiten letnada:

ingrese la descripción de la imagen aquí


Cómo realizar un seguimiento del soporte del navegador

Para obtener una descripción actualizada de qué navegadores admiten la letdeclaración al momento de leer esta respuesta, consulte esta Can I Usepágina .


(*) Las variables de ámbito global y funcional pueden inicializarse y utilizarse antes de declararse porque las variables de JavaScript se izan . Esto significa que las declaraciones siempre están en lo más alto del alcance.

(**) Las variables de ámbito de bloque no se izan

John Slegers
fuente
14
con respecto a la respuesta v4: ¡ iES conocido en todas partes en el bloque de funciones! ¡Comienza como undefined(debido al izado) hasta que asignes un valor! ps: lettambién se iza (en la parte superior del bloque que contiene), pero dará un ReferenceErrorcuando se hace referencia en el bloque antes de la primera asignación. (ps2: soy un tipo pro-punto y coma, pero realmente no necesitas un punto y coma después de un bloqueo). Dicho esto, ¡gracias por agregar el control de realidad con respecto al soporte!
GitaarLAB
@GitaarLAB: según la red de desarrolladores de Mozilla : "En ECMAScript 2015, los enlaces no están sujetos a elevación variable, lo que significa que las declaraciones no se mueven a la parte superior del contexto de ejecución actual". - De todos modos, hice algunas mejoras en mi respuesta que deberían aclarar la diferencia en el comportamiento de elevación entre lety var!
John Slegers
1
Su respuesta mejoró mucho (lo revisé a fondo). Tenga en cuenta que el mismo enlace al que hizo referencia en su comentario también dice: "La variable (let) está en una" zona muerta temporal "desde el inicio del bloque hasta que se procese la inicialización". Eso significa que el 'identificador' (la cadena de texto 'reservada' para señalar 'algo') ya está reservada en el alcance relevante, de lo contrario, pasaría a formar parte del alcance raíz / host / ventana. Para mí personalmente, 'izar' significa nada más que reservar / vincular los 'identificadores' declarados a su alcance relevante; excluyendo su inicialización / asignación / modificabilidad!
GitaarLAB
Y .. + 1. Ese artículo de Kyle Simpson que vinculaste es una excelente lectura, ¡gracias por eso! También está claro acerca de la "zona muerta temporal", también conocida como "TDZ". Una cosa interesante que me gustaría agregar: lo leí en MDN lety constse me recomendó usar solo cuando realmente necesita su funcionalidad adicional , porque aplicar / verificar estas características adicionales (como const de solo escritura) resulta en 'más trabajo '(y nodos de alcance adicionales en el árbol de alcance) para que los motores (actuales) apliquen / verifiquen / verifiquen / configuren.
GitaarLAB
1
Tenga en cuenta que MDN dice que IE HACE interpretar let correctamente. Cual es developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka Hesselink
146

Aquí hay una explicación de la letpalabra clave con algunos ejemplos.

letfunciona muy parecido var. La principal diferencia es que el alcance de una varvariable es la función de cierre completa

Esta tabla en Wikipedia muestra qué navegadores son compatibles con Javascript 1.7.

Tenga en cuenta que solo los navegadores Mozilla y Chrome lo admiten. IE, Safari y potencialmente otros no.

Ben S
fuente
55
La parte clave del texto del documento vinculado parece ser "dejar que funcione de manera muy parecida a var. La principal diferencia es que el alcance de una variable var es la función de cierre completa".
Michael Burr
50
Si bien es técnicamente correcto decir que IE no lo admite, es más correcto decir que es una extensión exclusiva de Mozilla.
olliej
55
@olliej, en realidad Mozilla está justo por delante del juego. Consulte la página 19 de ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton el
@TylerCrompton es solo el conjunto de palabras que se han reservado durante años. Cuando se agregó mozilla, fue puramente una extensión de mozilla, sin especificaciones relacionadas. ES6 debería definir el comportamiento de las declaraciones let, pero eso vino después de que mozilla introdujo la sintaxis. Recuerde que moz también tiene E4X, que está completamente muerto y solo moz.
olliej
99
IE11 agregó soporte para let msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
eloyesp
112

A la respuesta aceptada le falta un punto:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Lcf.vs
fuente
19
La respuesta aceptada NO explica este punto en su ejemplo. La respuesta aceptada solo lo demostró en un forinicializador de bucle, reduciendo drásticamente el alcance de la aplicación de las limitaciones de let. Votado
Jon Davis
37
@ stimpy77 Establece explícitamente "let tiene un alcance al bloque de cierre más cercano"; ¿Es necesario incluir todas las formas en que se manifiestan?
Dave Newton
66
hubo muchos ejemplos y ninguno de ellos demostró adecuadamente el asunto ... ¿Podría haber votado tanto la respuesta aceptada como esta?
Jon Davis
55
Esta contribución demuestra que un "bloque" puede ser simplemente un conjunto de líneas entre corchetes; es decir, que no necesita estar asociado con cualquier tipo de flujo de control, de bucle, etc.
webelo
81

let

Alcance del bloque

Las variables declaradas con la letpalabra clave tienen un alcance de bloque, lo que significa que solo están disponibles en el bloque en el que se declararon.

En el nivel superior (fuera de una función)

En el nivel superior, las variables declaradas usando letno crean propiedades en el objeto global.

var globalVariable = 42;
let blockScopedVariable = 43;

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

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

Dentro de una función

Dentro de una función (pero fuera de un bloque), lettiene el mismo alcance que 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

Dentro de un bloque

letNo se puede acceder a las variables declaradas usando dentro de un bloque fuera de ese bloque.

{
  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

Dentro de un bucle

Las variables declaradas con letbucles in solo se pueden referenciar dentro de ese bucle.

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.

Lazos con cierres

Si utiliza en letlugar de varen un bucle, con cada iteración obtendrá una nueva variable. Eso significa que puede usar un cierre de forma segura dentro de un bucle.

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

Debido a la zona muerta temporal , letno se puede acceder a las variables declaradas usando antes de declararlas. Intentar hacerlo arroja un error.

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

No volver a declarar

No puede declarar la misma variable varias veces usando let. Tampoco puede declarar una variable letcon el mismo identificador que otra variable que se declaró usando 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

constes bastante similar a: lettiene un alcance de bloque y tiene TDZ. Sin embargo, hay dos cosas que son diferentes.

Sin reasignación

La variable declarada usando constno se puede reasignar.

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

Tenga en cuenta que no significa que el valor sea inmutable. Sus propiedades aún se pueden cambiar.

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

Si desea tener un objeto inmutable, debe usarlo Object.freeze().

Se requiere inicializador

Siempre debe especificar un valor al declarar una variable usando const.

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

Aquí hay un ejemplo de la diferencia entre los dos (soporte recién iniciado para Chrome):
ingrese la descripción de la imagen aquí

Como puede ver, la var jvariable todavía tiene un valor fuera del alcance del bucle for (Block Scope), pero la let ivariable no está definida fuera del alcance del bucle 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);

vlio20
fuente
2
¿Qué herramienta estoy viendo aquí?
Barton
20
Chrome devtools
vlio20
Como desarrollador de applets de escritorio para Cinnamon, no he estado expuesto a herramientas tan brillantes.
Barton
48

Existen algunas diferencias sutiles: el letalcance se comporta más como el alcance variable en más o menos cualquier otro idioma.

Por ejemplo, se extiende al bloque que los encierra, no existen antes de ser declarados, etc.

Sin embargo, vale la pena señalar que letes solo una parte de las nuevas implementaciones de Javascript y tiene diferentes grados de compatibilidad con el navegador .

olliej
fuente
11
También vale la pena señalar que ECMAScript es el estándar y letestá incluido en el borrador de la sexta edición y probablemente estará en la especificación final.
Richard Ayotte
23
Esa es la diferencia que hace 3 años: D
olliej
44
Simplemente me sorprendió esta pregunta y en 2012 sigue siendo el caso que solo admiten los navegadores Mozilla let. Safari, IE y Chome no lo hacen.
pseudosavant
2
La idea de crear accidentalmente un alcance de bloque parcial en un accidente es un buen punto, tenga cuidado, letno se iza, para usar una variable definida por una letdefinida en la parte superior de su bloque. Si tiene una ifdeclaración que es más que unas pocas líneas de código, puede olvidar que no puede usar esa variable hasta que se haya definido. GRAN PUNTO !!!
Eric Bishard
2
@EricB: sí y no: "En ECMAScript 2015, let izaremos la variable a la parte superior del bloque. Sin embargo, hacer referencia a la variable en el bloque antes de que la declaración de la variable dé como resultado un Error de referencia (mi nota: en lugar de una buena versión anterior undefined). La variable está en una 'zona muerta temporal' desde el inicio del bloque hasta que se procese la declaración ". Lo mismo ocurre con las "declaraciones de cambio porque solo hay un bloque subyacente". Fuente: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB
29

La diferencia principal es la diferencia de alcance , mientras que let solo puede estar disponible dentro del alcance que se declara, como en for loop, se puede acceder a var fuera del bucle, por ejemplo. De la documentación en MDN (ejemplos también de MDN):

let le permite declarar variables que tienen un alcance limitado al bloque, declaración o expresión en la que se usa. Esto es diferente a la palabra clave var , que define una variable globalmente o localmente para una función completa, independientemente del alcance del bloque.

Las variables declaradas por let tienen como alcance el bloque en el que están definidas, así como en cualquier subbloque contenido. De esta manera, deja que funcione de manera muy similar a la var . La principal diferencia es que el alcance de una variable var es toda la función de cierre:

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

En el nivel superior de programas y funciones, let , a diferencia de var , no crea una propiedad en el objeto global. Por ejemplo:

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

Cuando se usa dentro de un bloque, permite limitar el alcance de la variable a ese bloque. Tenga en cuenta la diferencia entre var cuyo ámbito está dentro de la función donde se declara.

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

Además, no olvide que es la función ECMA6, por lo que aún no es totalmente compatible, por lo que es mejor que siempre la transpile a ECMA5 usando Babel, etc. Para obtener más información sobre el sitio web de babel

Alireza
fuente
24
  • Variable sin elevación

    letno se elevará a todo el alcance del bloque en el que aparecen. Por el contrario, varpodría elevarse como se muestra a continuación.

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

    En realidad, Per @Bergi, Ambos vary letson izados .

  • Recolección de basura

    El alcance del bloque letes útil se relaciona con los cierres y la recolección de basura para reclamar memoria. Considerar,

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

    La clickdevolución de llamada del controlador no necesita la hugeDatavariable en absoluto. Teóricamente, después de las process(..)ejecuciones, la enorme estructura de datos hugeDatapodría ser recogida de basura. Sin embargo, es posible que algunos motores JS aún tengan que mantener esta gran estructura, ya queclick función tiene un cierre en todo el alcance.

    Sin embargo, el alcance del bloque puede convertir esta enorme estructura de datos en basura recolectada.

    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 bucles

    leten el bucle puede volver a vincularlo a cada iteración del bucle, asegurándose de reasignarle el valor desde el final de la iteración del bucle anterior. Considerar,

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

    Sin embargo, reemplace varconlet

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

    Debido a que letcrea un nuevo entorno léxico con esos nombres para a) la expresión inicializadora b) cada iteración (antes de evaluar la expresión de incremento), hay más detalles aquí .

zangw
fuente
44
Sí, se izan, pero se comportan como si no se izaran debido a la Zona muerta temporal (redoble de tambores): un nombre muy dramático para un identificador que no está accesible hasta que se declara :-)
Drenai
¿Entonces let es izado pero no disponible? ¿Cómo es eso diferente de 'no izado'?
N-ate
Esperemos que Brian o Bergi vuelvan a responder esto. ¿Es la declaración de let izado, pero no la asignación? ¡Gracias!
N-ate el
1
@ N-ate, Aquí hay una publicación de Bergi, tal vez puedas encontrar la respuesta.
zangw
Es interesante que incluso se llame izar cuando se trata de alquilar. Entiendo que técnicamente el motor de análisis lo está capturando previamente, pero para todos los efectos, un programador debe tratarlo como si no existiera. La elevación de var, por otro lado, tiene implicaciones para un programador.
N-ate el
19

Aquí hay un ejemplo para agregar a lo que otros ya han escrito. Suponga que desea hacer una matriz de funciones, adderFunctionsdonde cada función toma un solo argumento de Número y devuelve la suma del argumento y el índice de la función en la matriz. Intentar generar adderFunctionscon un bucle usando la varpalabra clave no funcionará de la manera ingenua que alguien podría esperar:

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

El proceso anterior no genera la matriz de funciones deseada porque iel alcance se extiende más allá de la iteración del forbloque en el que se creó cada función. En cambio, al final del ciclo, el icierre en cada función se refiere al ivalor de al final del ciclo (1000) para cada función anónima en adderFunctions. Esto no es lo que queríamos en absoluto: ahora tenemos una matriz de 1000 funciones diferentes en la memoria con exactamente el mismo comportamiento. Y si posteriormente actualizamos el valor de i, la mutación afectará a todos losadderFunctions .

Sin embargo, podemos intentarlo nuevamente usando la letpalabra clave:

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

Esta vez, ise recupera en cada iteración del forbucle. Cada función ahora mantiene el valor de ien el momento de la creación de la función y se adderFunctionscomporta como se esperaba.

Ahora, mezcla imágenes de los dos comportamientos y probablemente verás por qué no se recomienda mezclar el más nuevo lety constel más antiguo varen el mismo script. Hacerlo puede resultar en un código espectacularmente 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

No dejes que esto te pase a ti. Usa una pelusa.

NOTA: Este es un ejemplo de enseñanza destinado a demostrar el comportamiento var/ leten bucles y con cierres de funciones que también serían fáciles de entender. Esta sería una forma terrible de sumar números. Pero la técnica general de capturar datos en el cierre de funciones anónimas podría encontrarse en el mundo real en otros contextos. YMMV.

abroz
fuente
2
@aborz: también una sintaxis de función anónima muy interesante en el segundo ejemplo. Es justo lo que estoy acostumbrado en C #. He aprendido algo hoy.
Barton
Corrección: Técnicamente, la sintaxis de la función de flecha descrita aquí => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton
3
En realidad, no necesitas let value = i;. La fordeclaración crea un bloque léxico.
Cepillo de dientes
17

La diferencia está en el alcance de las variables declaradas con cada uno.

En la práctica, hay una serie de consecuencias útiles de la diferencia en el alcance:

  1. letlas variables solo son visibles en su bloque de cierre más cercano ( { ... }).
  2. letLas variables solo se pueden usar en líneas de código que ocurren después de que se declara la variable (¡aunque se hayan izado !).
  3. letlas variables no pueden ser redeclaradas por un posterior varo let.
  4. Las letvariables globales no se agregan al windowobjeto global .
  5. letLas variables son fáciles de usar con los cierres (no causan condiciones de carrera ).

Las restricciones impuestas por letreducir la visibilidad de las variables y aumentar la probabilidad de que las colisiones inesperadas de nombres se encuentren temprano. Esto hace que sea más fácil rastrear y razonar sobre las variables, incluida su accesibilidad (lo que ayuda a recuperar la memoria no utilizada).

En consecuencia, letes menos probable que las variables causen problemas cuando se usan en programas grandes o cuando los marcos desarrollados independientemente se combinan de formas nuevas e inesperadas.

varaún puede ser útil si está seguro de que desea el efecto de enlace único al usar un cierre en un bucle (# 5) o para declarar variables globales visibles externamente en su código (# 4). El uso de varpara exportaciones puede suplantarse si exportmigra fuera del espacio del transpilador al idioma central.

Ejemplos

1. Sin uso fuera del bloque de cierre más cercano: este bloque de código arrojará un error de referencia porque el segundo uso de xocurre fuera del bloque donde se declara con let:

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

En contraste, el mismo ejemplo con varobras.

2. Sin uso antes de la declaración:
este bloque de código arrojará un ReferenceErrorantes de que el código pueda ejecutarse porque xse usa antes de que se declare:

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

Por el contrario, el mismo ejemplo con varanálisis y ejecuciones sin lanzar ninguna excepción.

3. Sin redeclaración: el siguiente código demuestra que una variable declarada con letno se puede volver a declarar más tarde:

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

4. Globales no vinculados 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. Uso fácil con cierres: las variables declaradas con varno funcionan bien con cierres dentro de bucles. Aquí hay un bucle simple que genera la secuencia de valores que la variable itiene en diferentes momentos:

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

Específicamente, esto produce:

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

En JavaScript, a menudo utilizamos variables en un tiempo significativamente más tarde que cuando se crean. Cuando demostramos esto retrasando la salida con un cierre pasado a setTimeout:

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

... la salida permanece sin cambios mientras nos mantengamos let. Por el contrario, si hubiéramos usado en su var ilugar:

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

... el bucle genera inesperadamente "i is 5" cinco veces:

i is 5
i is 5
i is 5
i is 5
i is 5
Mormegil
fuente
55
# 5 no es causado por una condición de carrera. Al usar en varlugar de let, el código es equivalente a: var i = 0; while (i < 5) { doSomethingLater(); i++; } iestá fuera del cierre, y para el momento en que doSomethingLater()se ejecuta, iya se ha incrementado 5 veces, por lo tanto, la salida es i is 5cinco veces. Al usar let, la variable iestá dentro del cierre, por lo que cada llamada asíncrona obtiene su propia copia en ilugar de usar la 'global' que se creó con var.
Daniel T.
@DanielT .: No creo que la transformación de levantar la definición variable del inicializador de bucle explique nada. Esa es simplemente la definición normal de la semántica de for. Una transformación más precisa, aunque más complicada, es la clásica for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i is $ {j} ), 125/*ms*/); })(i); }que introduce un "registro de activación de función" para guardar cada valor icon el nombre jdentro de la función.
mormegil
14

Que las siguientes dos funciones muestren la diferencia:

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

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

let es interesante, porque nos permite hacer algo como esto:

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

Lo que resulta en contar [0, 7].

Mientras

(() => {
    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 cuenta [0, 1].

Dmitry
fuente
2
Esta es la primera vez que he visto a alguien actuar como si fuera deseable un sombreado variable. no, el propósito de let no es permitir el sombreado
John Haugeland
1
¿propósito? es una construcción, puedes usarla como quieras, una de las formas interesantes es así.
Dmitry
13

Función VS alcance del bloque:

La principal diferencia entre vary letes que las variables declaradas con varson de ámbito de función . Mientras que las funciones declaradas con letson de ámbito de bloque . Por ejemplo:

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 

variables con var:

Cuando testVarse llama a la primera función, la variable foo, declarada con var, todavía es accesible fuera de la ifinstrucción. Esta variable fooestaría disponible en todas partes dentro del alcance de la testVar función .

variables con let:

Cuando testLetse llama a la segunda función, la barra variable, declarada con let, solo es accesible dentro de la ifinstrucción. Porque las variables declaradas con letson de ámbito de bloque (donde un bloque es el código entre llaves if{}, por ejemplo for{}, function{}).

let las variables no se izan:

Otra diferencia entre vary letes que las variables con declarado con let no se izan . Un ejemplo es la mejor manera de ilustrar este comportamiento:

variables con let no ser izadas:

console.log(letVar);

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

variables con var do get Arbolada:

console.log(varVar);

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

Global letno se apega a window:

Una variable declarada con leten el ámbito global (que es código que no está en una función) no se agrega como una propiedad en el windowobjeto global . Por ejemplo (este código está en alcance global):

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


¿Cuándo se debe letusar var?

Utilizar letmás varcada vez que pueda, ya que es simplemente cuyo ámbito más específico. Esto reduce los posibles conflictos de nombres que pueden ocurrir cuando se trata con una gran cantidad de variables. varpuede usarse cuando desea que una variable global esté explícitamente en el windowobjeto (siempre considere cuidadosamente si esto es realmente necesario).

Willem van der Veen
fuente
9

También parece que, al menos en Visual Studio 2015, TypeScript 1.5, "var" permite múltiples declaraciones del mismo nombre de variable en un bloque, y "let" no.

Esto no generará un error de compilación:

var x = 1;
var x = 2;

Esta voluntad:

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

var es la variable de alcance global (con capacidad de elevación).

lety constes el alcance del bloque.

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

Musulmán Shahsavan
fuente
8

Cuando usas let

La letpalabra clave adjunta la declaración de variable al alcance de cualquier bloque (comúnmente un { .. }par) en el que está contenida. En otras palabras, letsecuestra implícitamente el alcance de cualquier bloque para su declaración de variable.

letno se puede acceder a las variables en el windowobjeto porque no se puede acceder globalmente.

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

Cuando usas var

var y las variables en ES5 tienen ámbitos en las funciones, lo que significa que las variables son válidas dentro de la función y no fuera de la función misma.

varSe puede acceder a las variables en el windowobjeto porque no se puede acceder globalmente.

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

Si quieres saber más sigue leyendo a continuación

Una de las preguntas de entrevista más famosas sobre el alcance también puede ser suficiente para el uso exacto de lety varcomo a continuación;

Cuando usas let

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

Esto es porque cuando se usa let , para cada iteración de bucle, la variable tiene un alcance y tiene su propia copia.

Cuando usas var

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

Esto se debe a que, cuando se usa var, para cada iteración de bucle, la variable tiene un alcance y una copia compartida.

Ankur Soni
fuente
8

En términos más básicos,

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

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

⚡️ Sandbox para jugar ↓

Editar let vs var

Hasan Sefa Ozalp
fuente
7

Si leo las especificaciones correctamente, let afortunadamente también se puede aprovechar para evitar las funciones de auto invocación que se usan para simular miembros privados, un patrón de diseño popular que disminuye la legibilidad del código, complica la depuración, que no agrega protección de código real u otro beneficio, excepto tal vez satisfacer a alguien deseo de semántica, así que deja de usarlo. /despotricar

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

Consulte ' Emulación de interfaces privadas '

Daniel Sokolowski
fuente
¿Puede explicar cómo las expresiones de función invocadas de inmediato no proporcionan "protección de código" y lo lethacen? (Supongo que te refieres a IIFE con "función de auto invocación".)
Robert Siemer
¿Y por qué te pones hiddenPropertyen el constructor? Solo hay uno hiddenPropertypara todas las instancias en su "clase".
Robert Siemer
4

Algunos hacks 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 y 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)
zloctb
fuente
por favor, ¿qué significa esto let { type, name, value } = node;? creas un nuevo objeto con 3 propiedades tipo / nombre / valor e inicializas con los valores de propiedades del nodo?
AlainIb
En el ejemplo 3, está volviendo a declarar un nodo que causa una excepción. Todos estos ejemplos también funcionan perfectamente con var.
Rehan Haider
4

let vs var. Se trata de alcance .

Las variables var son globales y se puede acceder básicamente a todas partes, mientras que las variables let no son globales y solo existen hasta que un paréntesis de cierre las mata.

Vea mi ejemplo a continuación y observe cómo la variable lion (let) actúa de manera diferente en los dos console.logs; queda fuera de alcance en la segunda consola.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.
daCoda
fuente
4

ES6 introdujo dos nuevas palabras clave ( let y const ) alternativas a la var .

Cuando necesite una desaceleración de nivel de bloque, puede usar let y const en lugar de var.

La siguiente tabla resume la diferencia entre var, let y const

ingrese la descripción de la imagen aquí

Srikrushna
fuente
3

let es parte de es6. Estas funciones explicarán la diferencia de manera fácil.

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

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

A continuación se muestra cómo 'let' y 'var' son diferentes en el alcance:

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

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

El gfoo, definido por letinicialmente está en el alcance global , y cuando declaramos gfoonuevamente dentro del alcance,if clause su alcance cambió y cuando se asigna un nuevo valor a la variable dentro de ese alcance, no afecta el alcance global.

Mientras que hfoo, definido por varestá inicialmente en el alcance global , pero nuevamente cuando lo declaramos dentro del if clause, considera el alcance global hfoo, aunque var se ha utilizado nuevamente para declararlo. Y cuando reasignamos su valor, vemos que el alcance global hfoo también se ve afectado. Esta es la principal diferencia.

Piklu Dey
fuente
2

Como se ha mencionado más arriba:

La diferencia es el alcance. varse limita al bloque de funciones más cercano y letse limita al bloque de cierre más cercano , que puede ser más pequeño que un bloque de funciones. Ambos son globales si están fuera de cualquier bloque. Veamos un ejemplo:

Ejemplo 1:

En mis dos ejemplos tengo una función myfunc. myfunccontiene una variable myvarigual a 10. En mi primer ejemplo verifico si myvares igual a 10 ( myvar==10). En caso afirmativo, debo declarar una variable myvar(ahora tengo dos variables myvar) usando la varpalabra clave y asignarle un nuevo valor (20). En la siguiente línea imprimo su valor en mi consola. Después del bloque condicional, imprimo nuevamente el valor de myvaren mi consola. Si nos fijamos en la salida de myfunc, myvartiene un valor igual a 20.

dejar palabra clave

Ejemplo2: en mi segundo ejemplo, en lugar de usar la varpalabra clave en mi bloque condicional, declaro que myvarusa la letpalabra clave. Ahora cuando llamo myfunc obtengo dos salidas diferentes: myvar=20y myvar=10.

Entonces la diferencia es muy simple, es decir, su alcance.

N Randhawa
fuente
3
No publique imágenes de código, se considera una mala práctica en SO, ya que no se podrá buscar para futuros usuarios (así como problemas de accesibilidad). Además, esta respuesta no agrega nada que otras respuestas aún no hayan abordado.
inostia
2

Quiero vincular estas palabras clave al contexto de ejecución, porque el contexto de ejecución es importante en todo esto. El contexto de ejecución tiene dos fases: una fase de creación y una fase de ejecución. Además, cada contexto de ejecución tiene un entorno variable y un entorno externo (su entorno léxico).

Durante la fase de creación de un contexto de ejecución, var, let y const todavía almacenarán su variable en la memoria con un valor indefinido en el entorno variable del contexto de ejecución dado. La diferencia está en la fase de ejecución. Si usa una variable de referencia definida con var antes de que se le asigne un valor, simplemente no estará definida. No se planteará ninguna excepción.

Sin embargo, no puede hacer referencia a la variable declarada con let o const hasta que se declare. Si intenta usarlo antes de que se declare, se generará una excepción durante la fase de ejecución del contexto de ejecución. Ahora la variable aún estará en la memoria, cortesía de la Fase de Creación del Contexto de Ejecución, pero el Motor no le permitirá usarla:

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

Con una variable definida con var, si el motor no puede encontrar la variable en el entorno variable actual del contexto de ejecución, subirá por la cadena de alcance (el entorno externo) y verificará la variable en el entorno variable del entorno externo. Si no puede encontrarlo allí, continuará buscando la cadena de alcance. Este no es el caso con let y const.

La segunda característica de let es que introduce el alcance del bloque. Los bloques están definidos por llaves. Los ejemplos incluyen bloques de funciones, si son bloques, para bloques, etc. Cuando declara una variable con let dentro de un bloque, la variable solo está disponible dentro del bloque. De hecho, cada vez que se ejecuta el bloque, como dentro de un bucle for, creará una nueva variable en la memoria.

ES6 también introduce la palabra clave const para declarar variables. const también tiene un alcance de bloque. La diferencia entre let y const es que las variables const deben declararse utilizando un inicializador, o generará un error.

Y, finalmente, cuando se trata del contexto de ejecución, las variables definidas con var se adjuntarán al objeto 'this'. En el contexto de ejecución global, ese será el objeto de ventana en los navegadores. Este no es el caso de let o const.

Donato
fuente
2

Creo que los términos y la mayoría de los ejemplos son un poco abrumadores. El problema principal que tuve personalmente con la diferencia es entender qué es un "Bloque". En algún momento me di cuenta de que un bloque sería cualquier llave, excepto la IFdeclaración. un paréntesis {de apertura de una función o bucle definirá un nuevo bloque, cualquier cosa definida letdentro de él, no estará disponible después del corchete }de cierre de la misma cosa (función o bucle); Con eso en mente, fue más fácil de entender:

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

Demencial
fuente
1

Ahora creo que hay un mejor alcance de las variables para un bloque de declaraciones 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
}

Creo que la gente comenzará a usar let here después para que tengan un alcance similar en JavaScript como otros lenguajes, Java, C #, etc.

Las personas que no tenían una comprensión clara sobre el alcance en JavaScript solían cometer el error antes.

La elevación no es compatible con el uso let.

Con este enfoque, los errores presentes en JavaScript se eliminan.

Consulte ES6 en profundidad: let y const para comprenderlo mejor.

swaraj patil
fuente
Para una comprensión más profunda al respecto, consulte el enlace - davidwalsh.name/for-and-against-let
swaraj patil el
1

Este artículo define claramente la diferencia entre var, let y const

const es una señal de que el identificador no será reasignado.

let, es una señal de que la variable puede reasignarse, como un contador en un bucle o un intercambio de valores en un algoritmo. También indica que la variable se usará solo en el bloque en el que está definida, que no siempre es la función que contiene todo.

varahora es la señal más débil disponible cuando define una variable en JavaScript. La variable se puede reasignar o no, y la variable se puede usar o no para una función completa, o solo con el propósito de un bloque o bucle.

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

anandharshan
fuente