¿Las variables declaradas con let o const no se elevan en ES6?


He estado jugando con ES6 durante un tiempo y me di cuenta de que las variables while declaradas con var se elevan como se esperaba...

console.log(typeof name); // undefined
var name = "John";

...las variables declaradas con let o const parecen tener algunos problemas con el levantamiento:

console.log(typeof name); // ReferenceError
let name = "John";

Y

console.log(typeof name); // ReferenceError
const name = "John";

¿Significa esto que las variables declaradas con let o const no se izan? ¿Qué está pasando realmente aquí? Hay alguna diferencia entre let y const en este asunto?

Author: Michał Perłakowski, 2015-07-04

3 answers

@thefourtheye tiene razón al decir que estas variables no se puede acceder antes de que se declaren. Sin embargo, es un poco más complicado que eso.

¿Las variables declaradas con let o const no están izadas? ¿Qué está pasando realmente aquí?

Todas las declaraciones (var, let, const, function, function*, class) son "izada" en JavaScript. Esto significa que si se declara un nombre en un ámbito, en ese ámbito el identificador siempre haga referencia a esa variable particular:

x = "global";
// function scope:
(function() {
    x; // not "global"

    var/let/… x;
}());
// block scope (not for `var`s):
{
    x; // not "global"

    let/const/… x;
}

Esto es cierto tanto para ámbitos de función como de bloque1.

La diferencia entre var/function/function* declaraciones y let/const/class declaraciones es el inicialización.
Los primeros se inicializan con undefined o la función (generator) justo cuando se crea el enlace en la parte superior del ámbito. Sin embargo, las variables declaradas léxicamente permanecen no inicializadas. Esto significa que un ReferenceError la excepción se lanza cuando intenta acceder a ella. Solo se inicializará cuando el let/const/class se evalúa la declaración, todo lo anterior (arriba) que se llama la zona muerta temporal .

x = y = "global";
(function() {
    x; // undefined
    y; // Reference error: y is not defined

    var x = "local";
    let y = "local";
}());

Observe que una instrucción let y; inicializa la variable con undefined como let y = undefined; tendría.

La zona muerta temporal no es una ubicación sintáctica, sino el tiempo entre la creación de la variable (ámbito) y la inicialización. No es un error para hacer referencia a la variable en el código por encima de la declaración siempre y cuando ese código no se ejecute (por ejemplo, un cuerpo de función o simplemente código muerto), y lanzará una excepción si accede a la variable antes de la inicialización, incluso si el código de acceso está debajo de la declaración (por ejemplo, en una declaración de función elevada que se llama demasiado pronto).

¿hay alguna diferencia entre let y const en este asunto?

No, funcionan igual en lo que respecta a la elevación considerar. La única diferencia entre ellos es que una constant debe ser y solo puede ser asignada en la parte inicializadora de la declaración (const one = 1;, tanto const one; como reasignaciones posteriores como one = 2 no son válidas).

1: var las declaraciones siguen funcionando solo en el nivel de función, por supuesto

 241
Author: Bergi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-11 14:28:42

Citando la especificación ECMAScript 6 (ECMAScript 2015) , let y const declaraciones sección,

Las variables se crean cuando se crea una instancia de su Entorno Léxico que contiene, pero no se puede acceder de ninguna manera hasta que se evalúe la vinculación LexicalBinding de la variable.

Entonces, para responder a su pregunta, sí, let y const hoist pero no puede acceder a ellos antes de que la declaración real se evalúe en tiempo de ejecución.

 62
Author: thefourtheye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-22 14:50:57

ES6 introduce Let variables que viene con block level scoping. Hasta ES5 no teníamos block level scoping, por lo que las variables que se declaran dentro de un bloque son siempre hoisted a nivel de función de alcance.

Básicamente Scope se refiere a dónde en su programa son visibles sus variables, lo que determina dónde se le permite usar las variables que ha declarado. En ES5 tenemos global scope,function scope and try/catch scope, con ES6 también obtenemos el alcance del nivel de bloque usando Let.

  • Cuando se define una variable con la palabra clave var, se conoce toda la función desde el momento en que se define.
  • Cuando se define una variable con la instrucción let solo se conoce en el bloque que se define.

     function doSomething(arr){
         //i is known here but undefined
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(var i=0; i<arr.length; i++){
             //i is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(let j=0; j<arr.length; j++){
             //j is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
     }
    
     doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
    

Si ejecuta el código, podría ver que la variable j solo se conoce en loop y no antes y después. Sin embargo, nuestra variable i se conoce en el entire function desde el momento en que se define en adelante.

Hay otra gran ventaja usando let ya que crea un nuevo entorno léxico y también une valor fresco en lugar de mantener una referencia antigua.

for(var i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

for(let i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

El primer bucle for siempre imprime el último valor, con let crea un nuevo ámbito y enlaza valores frescos imprimiéndonos 1, 2, 3, 4, 5.

Llegando a constants, funciona básicamente como let, la única diferencia es que su valor no se puede cambiar. En constantes se permite la mutación, pero no se permite la reasignación.

const foo = {};
foo.bar = 42;
console.log(foo.bar); //works

const name = []
name.push("Vinoth");
console.log(name); //works

const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.

console.log(age);

Si una constante se refiere a una object, siempre se referirá al object pero el object en sí puede ser cambiado (si es mutable). Si te gusta tener un object inmutable, puedes usar Object.freeze([])

 16
Author: Thalaivar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-11 06:46:36