¿Cuál es la diferencia entre usar “let” y “var” para declarar una variable en JavaScript?

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

¿Cuáles son las diferencias? ¿Cuándo debería let usar sobre var ?

La diferencia es el scope. var se dirige al bloque de funciones más cercano y se dirige al bloque de encerramiento 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.

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, arrojará una excepción ReferenceError.

Demo :

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

let también puede usarse para evitar problemas con cierres. Vincula el valor nuevo en lugar de mantener una referencia anterior 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 muestra un problema clásico de cierre de JavaScript. La referencia a la variable i se almacena en el cierre del manejador 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 contador que contiene 6, por lo que obtendrá seis en cada clic.

La solución general es envolver esto en una función anónima y pasarlo como argumento. Tales problemas también pueden evitarse ahora usando let lugar 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.

deja que las obras se parezcan mucho a var. La principal diferencia es que el scope de una variable var es toda la función adjunta

Esta tabla en Wikipedia muestra qué navegadores admiten 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 usando 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 mediante una instrucción let solo se conoce en el bloque en el que está definida, desde el momento en que se define. (**)

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, considere que las variables de ámbito de bloque no se conocen antes de que se declaren porque no están elevadas. Tampoco puede redeclarar 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 generan y que no producen ningún error en el caso de declaraciones múltiples.


¿Es seguro usar let hoy?

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

Hoy, sin embargo, definitivamente ese no es el caso. De hecho, necesitamos preguntarnos si es seguro usar la statement de let . La respuesta a esa pregunta depende de tu entorno:

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

  • Si está escribiendo un código JavaScript del lado del cliente y usa un transpiler (como Traceur ), puede usar la instrucción let seguridad, 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 no usa un transpiler, debe considerar la compatibilidad con el navegador.

¡Hoy, 8 de junio de 2018, todavía hay algunos navegadores que no admiten el uso de let !

enter image description here


Cómo realizar un seguimiento del soporte del navegador

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


(*) Las variables de ámbito global y funcional pueden inicializarse y utilizarse antes de que se declaren porque las variables de JavaScript son izadas . Esto significa que las declaraciones siempre son muy importantes.

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

La respuesta aceptada le falta un punto:

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

Hay algunas diferencias sutiles: el ámbito se comporta más como el ámbito variable en más o menos cualquier otro idioma.

Por ejemplo, alcanza el bloque de inclusión. No existen antes de que se declaren, etc.

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

Aquí hay un ejemplo de la diferencia entre los dos (soporte recién comenzado para Chrome): enter image description here

Como puede ver, la variable var j todavía tiene un valor fuera del scope del bucle for (Block Scope), 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); 

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 con let no 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 un funciton (pero fuera de un bloque), let tiene 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

No se puede acceder a las variables declaradas usando let 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 bucles de entrada 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. 

Bucles con cierres

Si usa let lugar de var en un bucle, con cada iteración obtendrá una nueva variable. Eso significa que puede usar con seguridad un cierre 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 mediante let antes de que se declaren. 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 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 -it's block-scoped y tiene TDZ. Sin embargo, hay dos cosas que son diferentes.

No volver a asignar

La variable declarada usando const no 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 usar Object.freeze() .

Inicializador es requerido

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

 const a; // SyntaxError: Missing initializer in const declaration 
  • Variable no alzando

    let se izará al scope completo del bloque en el que aparecen. Por el contrario, var podría izar 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, tanto var como let son izadas .

  • Recolección de basura

    El scope del bloque de let es útil para cierres y 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 callback del manejador de click no necesita la variable hugeData en absoluto. Teóricamente, después de que el process(..) ejecute, la enorme estructura de datos hugeData podría ser basura recolectada. Sin embargo, es posible que algún motor JS tenga que mantener esta enorme estructura, ya que la función de click tiene un cierre sobre todo el scope.

    Sin embargo, el scope del bloque puede hacer que esta gran estructura de datos sea recogida de 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 puede volver a vincularlo a cada iteración del bucle, asegurándose de volver a asignarle 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 var con let

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

    Porque let crear un nuevo entorno léxico con esos nombres para a) la expresión del inicializador b) cada iteración (antes de evaluar la expresión del 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 ciclo. De la documentación en MDN (ejemplos también de MDN):

let le permite declarar variables de scope limitado al bloque, statement o expresión en la que se utiliza. Esto es diferente de la palabra clave var , que define una variable de forma global o local para una función completa, independientemente del scope del bloque.

Las variables declaradas por let tienen como ámbito el bloque en el que están definidas, así como en cualquier subbloque contenido. De esta manera, deje que se parezca mucho a var . La principal diferencia es que el scope de una variable var es toda la función adjunta:

 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, 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 utiliza dentro de un bloque, let limita el scope de la variable a ese bloque. Tenga en cuenta 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 es totalmente compatible, por lo que siempre es mejor transstackrla a ECMA5 utilizando Babel, etc … para obtener más información acerca de visitar el sitio web babel

Aquí hay un ejemplo para agregar a lo que otros ya han escrito. Supongamos que desea crear una serie de funciones, adderFunctions , donde cada función toma un único argumento Number y devuelve la sum del argumento y el índice de la función en la matriz. Intentar generar adderFunctions con un bucle utilizando la palabra clave var no funcionará de la forma en 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 el conjunto deseado de funciones porque su scope va más allá de la iteración del bloque for en el que se creó cada función. En cambio, al final del ciclo, i en el cierre de cada función se refiere al valor de i al final del ciclo (1000) para cada función anónima en adderFunctions . Esto no es lo que queríamos en absoluto: ahora tenemos un conjunto 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 .

Sin embargo, podemos intentar de nuevo usando 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 se recupera en cada iteración del ciclo for . Cada función ahora conserva el valor de i en el momento de la creación de la función, y adderFunctions comporta como se esperaba.

Ahora, la imagen mezcla los dos comportamientos y probablemente veas por qué no se recomienda mezclar el nuevo let y const con el var anterior en el mismo script. Hacerlo puede dar como resultado 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. Use un linter.

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

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

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

  1. let variables let solo son visibles en su bloque adjunto más cercano ( { ... } ).
  2. let variables de let solo se pueden usar en líneas de código que ocurren después de que se declara la variable (¡a pesar de que están izadas !).
  3. let variables let no pueden ser redeclaradas por una var o let posterior.
  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].

Whereas

 (() => { 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].

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; 

Esta voluntad:

 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 

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) 

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.

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

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” .

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.

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