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

ECMAScript 6 introdujo la statement let .

He oído que se describe como una variable “local”, pero aún no estoy seguro de cómo se comporta de manera diferente a la palabra clave var .

¿Cuáles son las diferencias? ¿Cuándo debe let usar sobre var ?

30 Solutions collect form web for “¿Cuál es la diferencia entre usar “let” y “var”?”

La diferencia es el scope. var encuentra dentro del scope del bloque de función más cercano y se let scope del bloque envolvente más cercano, que puede ser más pequeño que un bloque de función. Ambos son globales si están fuera de cualquier bloque.

Además, las variables declaradas con let no son accesibles antes de que se declaren en su bloque adjunto. Como se ve en la demostración, esto lanzará una excepción ReferenceError.

Demostración :

 var html = ''; write('#### global ####\n'); write('globalVar: ' + globalVar); //undefined, but visible try { write('globalLet: ' + globalLet); //undefined, *not* visible } catch (exception) { write('globalLet: exception'); } write('\nset variables'); var globalVar = 'globalVar'; let globalLet = 'globalLet'; write('\nglobalVar: ' + globalVar); write('globalLet: ' + globalLet); function functionScoped() { write('\n#### function ####'); write('\nfunctionVar: ' + functionVar); //undefined, but visible try { write('functionLet: ' + functionLet); //undefined, *not* visible } catch (exception) { write('functionLet: exception'); } write('\nset variables'); var functionVar = 'functionVar'; let functionLet = 'functionLet'; write('\nfunctionVar: ' + functionVar); write('functionLet: ' + functionLet); } function blockScoped() { write('\n#### block ####'); write('\nblockVar: ' + blockVar); //undefined, but visible try { write('blockLet: ' + blockLet); //undefined, *not* visible } catch (exception) { write('blockLet: exception'); } for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) { write('\nblockVar: ' + blockVar); // visible here and whole function }; for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) { write('blockLet: ' + blockLet); // visible only here }; write('\nblockVar: ' + blockVar); try { write('blockLet: ' + blockLet); //undefined, *not* visible } catch (exception) { write('blockLet: exception'); } } function write(line) { html += (line ? line : '') + '
'; } functionScoped(); blockScoped(); document.getElementById('results').innerHTML = html;
 

let también puede ser usado para evitar problemas con los cierres. Enlaza valor nuevo en lugar de mantener una referencia antigua como se muestra en los ejemplos a continuación.

MANIFESTACIÓN

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

El código anterior demuestra un problema clásico de cierre de JavaScript. La referencia a la variable i se almacena en el cierre del controlador de clic, 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 obtiene seis en cada clic.

La solución general es envolver esto en una función anónima y pasar i como argumento. Tales problemas también se pueden evitar ahora usando let lugar de var como se muestra en el código a continuación.

DEMO (Probado en Chrome y Firefox 50)

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

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

Dejamos los trabajos muy parecidos a la var. La principal diferencia es que el scope de una variable var 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.

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

  • Una variable definida mediante una instrucción var se conoce a través de la función en la que está definida, desde el inicio de la función. (*)
  • Una variable definida utilizando una instrucción let solo se conoce en el bloque en el que se define, desde el momento en que se define en adelante. (**)

Para entender 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 j solo se conoce en el primer bucle for, pero no antes y después. Sin embargo, nuestra variable i es 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 están elevadas. Tampoco está permitido 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 scope global o funcional, que se elevan y no producen errores en caso de declaraciones múltiples.


¿Es seguro usarlo hoy?

Algunas personas dirían que en el futuro SOLAMENTE usaremos declaraciones de dejar y que las declaraciones de var será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, necesitamos preguntarnos si es seguro usar la statement let . La respuesta a esa pregunta depende de su entorno:

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

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

  • Si está escribiendo un código JavaScript del lado del cliente y usa un transpiler basado en Nodo (como el script de shell traceur o Babel ), puede usar la instrucción let forma segura. Y debido a que su navegador solo sabrá acerca del código transstackdo, los inconvenientes de rendimiento deberían ser limitados.

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

    Todavía hay algunos navegadores que no son compatibles con en absoluto:

introduzca la descripción de la imagen aquí


Cómo realizar un seguimiento de la compatibilidad del navegador

Para obtener una descripción actualizada de qué navegadores son compatibles con la statement de let en el momento de leer esta respuesta, consulte esta página Can I Use ?


(*) Las variables de scope global y funcional se pueden inicializar y usar antes de declararse porque las variables de JavaScript están elevadas . Esto significa que las declaraciones están siempre en la parte superior del scope.

(**) Las variables del ámbito del bloque no son elevadas.

A la respuesta aceptada le falta un punto:

 { let a = 123; }; console.log(a); // ReferenceError: a is not defined 

let

Alcance del bloque

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

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

En el nivel superior, las variables declaradas utilizando no let crear 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 funcion

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

Las variables declaradas usando let dentro de un bloque no pueden accederse 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 bucles de entrada pueden ser referenciadas solo 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. 

Bucles con cierres

Si utiliza let lugar de var en 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 , no se puede acceder a las variables declaradas utilizando let 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 re-declarar

No puedes declarar la misma variable varias veces usando let . Tampoco puede declarar una variable usando let con el mismo identificador que otra variable que fue declarada 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

const es bastante similar a let que let de ámbito de bloques y tiene TDZ. Hay, sin embargo, dos cosas que son diferentes.

Sin reasignación

La variable declarada usando const no puede ser reasignada.

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

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

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

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

Se requiere inicializador

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

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

Hay algunas diferencias sutiles: let scope se comporte más como el scope variable en más o menos otros idiomas.

Por ejemplo, se dirige al bloque adjunto, no existen antes de que se declaren, etc.

Sin embargo, vale la pena señalar que let solo una parte de las implementaciones más recientes de Javascript y que tiene diversos grados de compatibilidad con el navegador .

Aquí hay un ejemplo de la diferencia entre los dos (el soporte acaba de comenzar para Chrome): introduzca la descripción de la imagen aquí

Como puede ver, la variable var j sigue teniendo un valor fuera del scope del bucle for (Ámbito del bloque), pero la variable let i no está definida fuera del scope 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); 
  • Variable No Levantamiento

    let permitiremos elevar todo el scope del bloque en el que aparecen. Por el contrario, var podría elevar 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, ambas var y let son izados .

  • Recolección de basura

    El ámbito de locking de let es útil se relaciona con los cierres y la recolección de basura para recuperar memoria. Considerar,

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

    La callback del controlador de click no necesita la variable hugeData en absoluto. Teóricamente, después de que process(..) ejecuta el process(..) , la enorme estructura de datos hugeData podría ser recogida de basura. Sin embargo, es posible que algún motor JS aún tenga que mantener esta enorme estructura, ya que la función de click tiene un cierre en todo el scope.

    Sin embargo, el ámbito de bloque puede hacer que esta enorme estructura de datos se recoja en la basura.

     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

    let el bucle pueda volver a vincularlo a cada iteración del bucle, asegurándose de volver a asignarle el valor del 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 var con let

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

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

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

let le permite declarar variables que están limitadas en su scope al bloque, la statement o la expresión en la que se utiliza. Esto es diferente a la palabra clave var , que define una variable global o localmente para una función completa, independientemente del scope del bloque.

Las variables declaradas por let tienen como su scope el bloque en el que están definidas, así como en cualquier sub-bloque contenido. De esta manera, vamos a trabajar de manera muy parecida a la var . La principal diferencia es que el scope de una variable var es la función de cierre completa:

 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 progtwigs y funciones, 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 utiliza dentro de un bloque, permite limitar el scope de la variable a ese bloque. Note la diferencia entre var cuyo scope 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 está totalmente soportada, por lo que es mejor que siempre la transfiera a ECMA5 usando Babel, etc. Para obtener más información sobre el sitio web de babel, visite

Aquí hay un ejemplo para agregar a lo que otros ya han escrito. Supongamos que desea realizar una matriz de funciones, funciones de adderFunctions , donde cada función toma un solo argumento de Número y devuelve la sum del argumento y el índice de la función en la matriz. Tratar de generar adderFunctions con un bucle usando la palabra clave var no funcionará de la manera que alguien podría esperar ingenuamente:

 // 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 el scope de i extiende más allá de la iteración del bloque for en el que se creó cada función. En cambio, al final del bucle, la i en el cierre de cada función hace referencia al valor de i al final del bucle (1000) para cada función anónima en funciones de 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 todas las adderFunctions del adderFunctions .

Sin embargo, podemos volver a intentarlo utilizando la palabra clave 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 

Esta vez, i es rebote en cada iteración del bucle for . Cada función ahora mantiene el valor de i en el momento de la creación de la función, y las funciones de adderFunctions comportan como se espera.

Ahora, la imagen mezcla los dos comportamientos y probablemente verá por qué no se recomienda mezclar las nuevas let y const con las var más antiguas en 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 

Don’t let this happen to you. Use a linter.

NOTE: This is a teaching example intended to demonstrate the var / let behavior in loops and with function closures that would also be easy to understand. This would be a terrible way to add numbers. But the general technique of capturing data in anonymous function closures might be encountered in the real world in other contexts. YMMV.

The difference is in the scope of the variables declared with each.

In practice, there are a number of useful consequences of the difference in scope:

  1. let variables are only visible in their nearest enclosing block ( { ... } ).
  2. let variables are only usable in lines of code that occur after the variable is declared (even though they are hoisted !).
  3. let variables may not be redeclared by a subsequent var or let .
  4. Global let variables are not added to the global window object.
  5. let variables are easy to use with closures (they do not cause race conditions ).

The restrictions imposed by let reduce the visibility of the variables and increase the likelihood that unexpected name collisions will be found early. This makes it easier to track and reason about variables, including their reachability (helping with reclaiming unused memory).

Consequently, let variables are less likely to cause problems when used in large programs or when independently-developed frameworks are combined in new and unexpected ways.

var may still be useful if you are sure you want the single-binding effect when using a closure in a loop (#5) or for declaring externally-visible global variables in your code (#4). Use of var for exports may be supplanted if export migrates out of transpiler space and into the core language.

Ejemplos

1. No use outside nearest enclosing block: This block of code will throw a reference error because the second use of x occurs outside of the block where it is declared with let :

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

In contrast, the same example with var works.

2. No use before declaration:
This block of code will throw a ReferenceError before the code can be run because x is used before it is declared:

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

In contrast, the same example with var parses and runs without throwing any exceptions.

3. No redeclaration: The following code demonstrates that a variable declared with let may not be redeclared later:

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

4. Globals not attached to 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. Easy use with closures: Variables declared with var do not work well with closures inside loops. Here is a simple loop that outputs the sequence of values that the variable i has at different points in time:

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

Specifically, this outputs:

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

In JavaScript we often use variables at a significantly later time than when they are created. When we demonstrate this by delaying the output with a closure passed to setTimeout :

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

... the output remains unchanged as long as we stick with let . In contrast, if we had used var i instead:

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

... the loop unexpectedly outputs "i is 5" five times:

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

May the following two functions show the difference:

 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 is interesting, because it allows us to do something like this:

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

Which results in counting [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++); } } } })(); 

Only counts [0, 1].

Function VS block scope:

The main difference between var and let is that variables declared with var are function scoped . Whereas functions declared with let are block scoped . 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 with var :

When the first function testVar gets called the variable foo, declared with var , is still accessible outside the if statement. This variable foo would be available everywhere within the scope of the testVar function .

variables with let :

When the second function testLet gets called the variable bar, declared with let , is only accessible inside the if statement. Because variables declared with let are block scoped (where a block is the code between curly brackets eg if{} , for{} , function{} ).

let variables don’t get hoisted:

Another difference between var and let is variables with declared with let don’t get hoisted . An example is the best way to illustrate this behavior:

variables with let don’t get hoisted:

 console.log(letVar); let letVar = 10; // referenceError, the variable doesn't get hoisted 

variables with var do get hoisted:

 console.log(varVar); var varVar = 10; // logs undefined, the variable gets hoisted 

Global let doesn’t get attached to window :

A variable declared with let in the global scope (which is code that is not in a function) doesn’t get added as a property on the global window object. For example (this code is in global scope):

 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 

When should let be used over var ?

Use let over var whenever you can because it is simply scoped more specific. This reduces potential naming conflicts which can occur when dealing with a large number of variables. var can be used when you want a global variable explicitly to be on the window object (always consider carefully if this is really necessary).

It also appears that, at least in Visual Studio 2015, TypeScript 1.5, “var” allows multiple declarations of the same variable name in a block, and “let” doesn’t.

This won’t generate a compile error:

 var x = 1; var x = 2; 

This will:

 let x = 1; let x = 2; 

var is global scope (hoist-able) variable.

let and const is block scope.

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 

When Using let

The let keyword attaches the variable declaration to the scope of whatever block (commonly a { .. } pair) it’s contained in. In other words, let implicitly hijacks any block’s scope for its variable declaration.

let variables cannot be accessed in the window object because they cannot be globally accessed.

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

When Using var

var and variables in ES5 has scopes in functions meaning the variables are valid within the function and not outside the function itself.

var variables can be accessed in the window object because they cannot be globally accessed.

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

If you want to know more continue reading below

one of the most famous interview questions on scope also can suffice the exact use of let and var as below;

When using let

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

This is because when using let , for every loop iteration the variable is scoped and has its own copy.

When using var

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

This is because when using var , for every loop iteration the variable is scoped and has shared copy.

If I read the specs right then let thankfully can also be leveraged to avoid self invoking functions used to simulate private only members – a popular design pattern that decreases code readability, complicates debugging, that adds no real code protection or other benefit – except maybe satisfying someone’s desire for semantics, so stop using it. /rant

 var SomeConstructor; { let privateScope = {}; SomeConstructor = function SomeConstructor () { this.someProperty = "foo"; privateScope.hiddenProperty = "bar"; } SomeConstructor.prototype.showPublic = function () { console.log(this.someProperty); // foo } SomeConstructor.prototype.showPrivate = function () { console.log(privateScope.hiddenProperty); // bar } } var myInstance = new SomeConstructor(); myInstance.showPublic(); myInstance.showPrivate(); console.log(privateScope.hiddenProperty); // error 

See ‘ Emulating private interfaces ‘

Some hacks with 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 and setter with 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 is a part of es6. These functions will explain the difference in easy way.

 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 } 

Previously there were only two scopes in JavaScript, ie functional and global. With ‘ let ‘ keyword JavaScript has now introduced block-level variables.

To have a complete understanding of the ‘let’ keyword, ES6: ‘let’ keyword to declare variable in JavaScript will help.

Now I think there is better scoping of variables to a block of statements using 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 } 

I think people will start using let here after so that they will have similar scoping in JavaScript like other languages, Java, C#, etc.

People with not a clear understanding about scoping in JavaScript used to make the mistake earlier.

Hoisting is not supported using let .

With this approach errors present in JavaScript are getting removed.

Refer to ES6 In Depth: let and const to understand it better.

This article clearly defines the difference between var, let and const

const is a signal that the identifier won’t be reassigned.

let , is a signal that the variable may be reassigned, such as a counter in a loop, or a value swap in an algorithm. It also signals that the variable will be used only in the block it’s defined in, which is not always the entire containing function.

var is now the weakest signal available when you define a variable in JavaScript. The variable may or may not be reassigned, and the variable may or may not be used for an entire function, or just for the purpose of a block or loop.

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

As mentioned above:

The difference is scoping. var is scoped to the nearest function block and let is scoped to the nearest enclosing block , which can be smaller than a function block. Both are global if outside any block.Lets see an example:

Example1:

In my both examples I have a function myfunc . myfunc contains a variable myvar equals to 10. In my first example I check if myvar equals to 10 ( myvar==10 ) . If yes, I agian declare a variable myvar (now I have two myvar variables)using var keyword and assign it a new value (20). In next line I print its value on my console. After the conditional block I again print the value of myvar on my console. If you look at the output of myfunc , myvar has value equals to 20.

let keyword

Example2: In my second example instead of using var keyword in my conditional block I declare myvar using let keyword . Now when I call myfunc I get two different outputs: myvar=20 and myvar=10 .

So the difference is very simple ie its scope.

introduzca la descripción de la imagen aquí

Take a look at this image, I created one very simple example for demonstration of const and let variables. As you can see, when you try to change const variable, you will get the error ( Attempting to override ‘name’ which is constant’ ), but take a look at let variable…

First we declare let age = 33 , and later assign some other value age = 34; , which is ok, we dont have any errors when we try to change let variable

As I am currently trying to get an in depth understanding of JavaScript I will share my brief research which contains some of the great pieces already discussed plus some other details in a different perspective.

Understanding the difference between var and let can be easier if we understand the difference between function and block scope .

Let’s consider the following cases:

 (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] 

when timer() gets called an ExecutionContext is created which will contain both the VariableEnvironment and all the LexicalEnvironments corresponding to each iteration.

And a simpler example

Function Scope

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

Block Scope

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

ECMAScript 6 added one more keyword to declare variables other the “const” other than “let”.

The primary goal of introduction of “let” and “const” over “var” is to have block scoping instead of traditional lexical scoping. This article explains very briefly difference between “var” and “let” and it also covers the discussion on “const” .

Check this link in MDN

 let x = 1; if (x === 1) { let x = 2; console.log(x); // expected output: 2 } console.log(x); // expected output: 1 

I want to link these keywords to the Execution Context, because the Execution Context is important in all of this. The Execution Context has two phases: a Creation Phase and Execution Phase. In addition, each Execution Context has a Variable Environment and Outer Environment (its Lexical Environment).

During the Creation Phase of an Execution Context, var, let and const will still store its variable in memory with an undefined value in the Variable Environment of the given Execution Context. The difference is in the Execution Phase. If you use reference a variable defined with var before it is assigned a value, it will just be undefined. No exception will be raised.

However, you cannot reference the variable declared with let or const until it is declared. If you try to use it before it is declared, then an exception will be raised during the Execution Phase of the Execution Context. Now the variable will still be in memory, courtesy of the Creation Phase of the Execution Context, but the Engine will not allow you to use it:

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

With a variable defined with var, if the Engine cannot find the variable in the current Execution Context’s Variable Environment, then it will go up the scope chain (the Outer Environment) and check the Outer Environment’s Variable Environment for the variable. If it cannot find it there, it will continue searching the Scope Chain. This is not the case with let and const.

The second feature of let is it introduces block scope. Blocks are defined by curly braces. Examples include function blocks, if blocks, for blocks, etc. When you declare a variable with let inside of a block, the variable is only available inside of the block. In fact, each time the block is run, such as within a for loop, it will create a new variable in memory.

ES6 also introduces the const keyword for declaring variables. const is also block scoped. The difference between let and const is that const variables need to be declared using an initializer, or it will generate an error.

And, finally, when it comes to the Execution Context, variables defined with var will be attached to the ‘this’ object. In the global Execution Context, that will be the window object in browsers. This is not the case for let or const.

  • ¿Cuál es la diferencia entre declarar objects javascript con var vs. function?
  • let vs var en javascript
  • ¿Puedo declarar la misma variable dos veces en diferentes loops en JavaScript?
  • JavaScript si var existe
  • Variables "var", variables "this" y variables "globales" - dentro de un Constructor JavaScript
  • Dos asignaciones en una línea
  • En javascript, ¿debería usar const en lugar de var siempre que sea posible?
  • ¿Alguien puede decodificar este javascript?
  • Javascript tiene muchos buenos JS marco (como Node.js AngularJS Vue.js React.js) es el mejor lenguaje de script.