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


ECMAScript 6 introducido el let declaració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 a la var palabra clave.

¿Cuáles son las diferencias? Cuando debe let ser usado sobre var?


3238
2018-04-17 20:09


origen


Respuestas:


La diferencia es el alcance. var tiene un alcance al bloque de función más cercano y let tiene el alcance al más cercano incluido bloque, 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.

Manifestació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 : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Global:

Son muy similares cuando se usan así fuera de un bloque de funciones.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

Sin embargo, las variables globales definidas con let no se agregará como propiedades en el global window objeto como los definidos con var.

console.log(window.me); // undefined
console.log(window.i); // 'able'

Función:

Son idénticos cuando se usan así en un bloque de funciones.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Bloquear:

Aquí está la diferencia. let solo es visible en for() lazo y var es visible para toda la función.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Redeclaración:

Asumiendo el modo estricto, var le permitirá volver a declarar la misma variable en el mismo ámbito. Por otra parte, let no:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.

4549
2018-05-27 10:16



let también se puede usar para evitar problemas con los 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. Referencia a la i variable se está almacenando 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 pasar i como argumento Tales problemas también se pueden evitar ahora mediante el uso de let en lugar var como se muestra en el código a continuación.

MANIFESTACIÓN (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) })
}

450
2018-04-17 20:11



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

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

Esta mesa 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.


129
2018-02-23 18:35



Cuál es la diferencia entre let y var?

  • Una variable definida usando un var declaración es conocida en todo la función se define en, desde el inicio de la función. (*)
  • Una variable definida usando un let declaración solo es conocida en el bloque se define en, desde el momento en que se define hacia 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 ciclo for, pero no antes y después. Sin embargo, nuestra variable i es conocido 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 usarlo? let ¿hoy?

Algunas personas argumentan que en el futuro SOLO usaremos declaraciones de let y que las declaraciones de var se volverán obsoletas. 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 el let declaración. La respuesta a esa pregunta depende de tu entorno:

  • Si está escribiendo código JavaScript del lado del servidor (Node.js), puedes usar el let declaración.

  • Si está escribiendo un código JavaScript del lado del cliente y usa un transpiler (como Traceur), puedes usar el let declaración, sin embargo, es probable que su código sea cualquier cosa menos ó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 son compatibles let!

enter image description here


Cómo realizar un seguimiento del soporte del navegador

Para obtener una descripción actualizada de qué navegadores admiten la let declaración al momento de leer esta respuesta, ver esta Can I Use página.


(*) Las variables con ámbito global y funcional se pueden inicializar y usar antes de que se declaren porque las variables de JavaScript son izada. Esto significa que las declaraciones siempre son muy importantes.

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


115
2018-06-02 20:59



La respuesta aceptada le falta un punto:

{
  let a = 123;
};

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

98
2018-04-17 21:38



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

p.ej. Alcanza el bloque delimitador. No existen antes de que se declaren, etc.

Sin embargo, vale la pena señalar que let es solo una parte de las implementaciones más nuevas de Javascript y tiene diversos grados de soporte de navegador.


40
2018-03-06 10:41



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

Como puedes ver var j variable todavía tiene un valor fuera del alcance del bucle for (Alcance del bloque), pero el let i la variable 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);


39
2017-11-23 22:52



let

Alcance del bloque

Variables declaradas usando el let Las palabras clave tienen un alcance de bloque, lo que significa que están disponibles solo en el bloquear en el que fueron declarados.

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

En el nivel superior, las variables declaradas usando let no crees 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 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

Variables declaradas usando let dentro de un bloque no se puede acceder 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

Variables declaradas con let los bucles in se pueden referenciar 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 en lugar de var en un ciclo, con cada iteración obtienes 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

Porque la zona muerta temporal, variables declaradas usando let no se puede acceder 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 puedes declarar una variable usando let con 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

const es bastante similar a let-tiene un alcance de bloque y tiene TDZ. Sin embargo, hay dos cosas que son diferentes.

No volver a asignar

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 quieres tener un objeto inmutable, debes 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

37
2018-01-17 15:11



  • Variable no alzando

    let será no alzamiento a todo el alcance del bloque en el que aparecen. Por el contrario, var podría alzar como abajo.

    {
       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 var y let son izadas.

  • Recolección de basura

    Alcance del bloque de let es útil se refiere a 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){
        //....
    });
    

    los click la devolución de llamada del manejador no necesita hugeData variable en absoluto. Teóricamente, después process(..) corre, la enorme estructura de datos hugeData podría ser basura recolectada Sin embargo, es posible que algún motor JS tenga que mantener esta gran estructura, ya que el click la función tiene un cierre sobre todo el alcance.

    Sin embargo, el alcance 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 en el bucle puede vuelve a unirlo a cada iteración del ciclo, asegurándose de volver a asignarle el valor desde el final de la iteración del ciclo 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 los nombres para a) la expresión del inicializador b) cada iteración (antes de evaluar la expresión del incremento), se dan más detalles aquí.


20
2018-03-22 14:39