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





13 Answers

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.

DEMO

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 utilizando 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) })
}
const cual cuando

ECMAScript 6 introdujo la declaración 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 ?




¿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, considera 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 alcance global o funcional, que se elevan y no producen errores en el caso de declaraciones múltiples.

¿Es seguro usarlo hoy?

Algunas personas argumentarán 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 detallado sobre por qué no es así .

Hoy, sin embargo, ese definitivamente no es el caso. De hecho, necesitamos preguntarnos si es seguro usar la declaración 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 la instrucción let forma segura.

  • Si está escribiendo un código de JavaScript del lado del cliente y usa un transpiler (como Traceur ), puede usar de manera segura la declaración let , sin embargo, es probable que su código sea todo menos óptimo con respecto al rendimiento.

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

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

Cómo realizar un seguimiento de la compatibilidad del navegador

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

(*) Las variables de alcance global y funcional pueden inicializarse y usarse antes de declararse porque las variables de JavaScript están hoisted . Esto significa que las declaraciones están siempre en la parte superior del alcance.

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




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

Las variables declaradas usando let dentro de un bloque no se pueden 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

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



Aquí hay un ejemplo de la diferencia entre los dos (el soporte acaba de comenzar para Chrome):

Como puede ver, la variable var j sigue teniendo un valor fuera del alcance del bucle for (Ámbito del bloque), pero la variable let i 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);




La principal diferencia es la diferencia de alcance , mientras que let solo puede estar disponible dentro del alcance 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 alcance al bloque, la declaración o la expresión en la que se utiliza. Esto es diferente a la palabra clave var , que define una variable globalmente, o localmente a una función completa, independientemente del alcance del bloque.

Las variables declaradas por let tienen como su alcance el bloque en el que están definidas, así como en cualquier sub-bloque contenido. De esta manera, dejemos que los trabajos se parezcan mucho a la var . La principal diferencia es que el alcance 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 programas 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 alcance de la variable a ese bloque. Note la diferencia entre var cuyo alcance 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, así que es mejor que siempre la transfiera a ECMA5 utilizando Babel, etc. Para obtener más información sobre el sitio web babel visite




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

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 se producen 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 cierres (no causan condiciones de carrera ).

Las restricciones impuestas letreducen la visibilidad de las variables y aumentan la probabilidad de que las colisiones de nombres inesperadas se encuentren pronto. Esto facilita el seguimiento y el razonamiento de las variables, incluida su reachability (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 de forma independiente se combinan de formas nuevas e inesperadas.

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

Ejemplos

1. Sin uso fuera del bloque de cierre más cercano: este bloque de código generará un error de referencia porque el segundo uso se xproduce 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 lanzará un ReferenceErrorcódigo antes de que se pueda ejecutar el código porque xse usa antes de declararlo

{
    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 varanaliza y ejecuta sin lanzar excepciones.

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

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

4. Globales no adheridos 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. Fácil uso con cierres: las variables declaradas varno funcionan bien con cierres dentro de los bucles. Aquí hay un bucle simple que genera la secuencia de valores que la variable itiene en diferentes puntos en el tiempo:

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 mucho 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 utilizado 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



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 el conteo [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].




var Es una variable de alcance global (elevable).

lety constes ámbito de 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




Si leo las especificaciones correctamente, let afortunadamente también se puede aprovechar para evitar las funciones de auto-invocación usadas para simular miembros exclusivos privados, un patrón de diseño popular que reduce la legibilidad del código, complica la depuración, que no agrega protección de código real ni otro beneficio 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 '.




Cuando usas let

La letpalabra clave adjunta la declaración de variable al alcance de cualquier bloque (generalmente un { .. }par) en el que se encuentra. En otras palabras, letsecuestra de forma implícita 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 a ellas 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 en sí.

varSe puede acceder a las variables en el windowobjeto porque no se puede acceder a ellas 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 con el uso exacto de lety varcomo se muestra 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 se debe a que, al usar let, para cada iteración de bucle, la variable tiene un ámbito 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, al usar var, para cada iteración de bucle, la variable tiene un ámbito y tiene una copia compartida.




Anteriormente, solo había dos ámbitos en JavaScript, es decir, funcional y global. Con ' let' palabra clave JavaScript ahora ha introducido block-levelvariables.

Para tener una comprensión completa de la palabra clave 'let', ES6: la palabra clave 'let' para declarar la variable en JavaScript ayudará.




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 ser reasignada, 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 se define, lo 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 puede o no ser reasignada, y la variable puede o no ser utilizada para una función completa, o solo para el propósito de un bloque o bucle.

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







Related