Czy zmienne deklarowane za pomocą let lub const nie są podnoszone w ES6?

Od jakiegoś czasu gram z ES6 i zauważyłem, że podczas gdy zmienne zadeklarowane z var są podnoszone zgodnie z oczekiwaniami...

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

...zmienne deklarowane przez let lub const wydają się mieć pewne problemy z podnoszeniem:

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

I

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

Czy to oznacza, że zmienne zadeklarowane przez let lub const nie są podnoszone? Co tu się naprawdę dzieje? Czy jest jakaś różnica między let i const w tej sprawie?

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

3 answers

@thefourtheye ma rację mówiąc, że te zmienne nie mogą być dostępne przed ich zadeklarowaniem. Jest to jednak nieco bardziej skomplikowane.

Czy zmienne deklarowane są przez let Czy const nie są podnoszone? Co tu się naprawdę dzieje?

Wszystkie deklaracje (var, let, const, function, function*, class) są "podnoszone" W JavaScript. Oznacza to, że jeśli nazwa jest zadeklarowana w zakresie, w tym zakresie identyfikator będzie zawsze odwołaj się do danej zmiennej:

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

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

    let/const/… x;
}

Jest to prawdą zarówno dla zakresów funkcyjnych, jak i blokowych1.

Różnica między var/function/function* deklaracje i let/const/class deklaracje są inicjalizacją .
Te pierwsze są inicjowane przez undefined lub funkcję (generator) po utworzeniu powiązania na górze zakresu. Zmienne leksykalne pozostają jednak niezainicjalizowane. Oznacza to, że a ReferenceError wyjątek jest wyrzucany, gdy próbujesz uzyskać do niego dostęp. Zostanie zainicjowany tylko wtedy, gdy let/const/class twierdzenie jest oceniane, wszystko przed (powyżej), który jest nazywany temporal dead zone .

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

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

Zauważ, że let y; Instrukcja inicjalizuje zmienną undefined tak jak let y = undefined;.

Temporal dead zone nie jest miejscem składniowym, ale raczej czasem pomiędzy utworzeniem zmiennej (scope) a inicjalizacją. To nie jest błąd odwoływania się do zmiennej w kodzie nad deklaracją tak długo, jak ten kod nie jest wykonywany (np. ciało funkcji lub po prostu martwy kod), i spowoduje wyświetlenie wyjątku, jeśli uzyskasz dostęp do zmiennej przed inicjalizacją, nawet jeśli kod dostępu znajduje się poniżej deklaracji (np. w deklaracji funkcji podniesionej, która jest wywoływana zbyt wcześnie).

Czy jest jakaś różnica między let i const w tej sprawie?

Nie, działają tak samo jak podnośniki / align = "left" / Jedyną różnicą między nimi jest to, że ant constmusi być i może być przypisany tylko w części inicjalizatora deklaracji (const one = 1;, zarówno const one;, jak i późniejsze przypisania, takie jak one = 2 są nieważne).

1: var deklaracje nadal działają tylko na poziomie funkcji, oczywiście

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-11 14:28:42

Cytowanie specyfikacji ECMAScript 6 (ECMAScript 2015) , let i const deklaracje sekcja,

Zmienne są tworzone, gdy ich zawierające środowisko leksykalne jest instancjowane, ale nie mogą być dostępne w żaden sposób, dopóki nie zostanie ocenione Leksykalbinding zmiennej .

Więc, aby odpowiedzieć na twoje pytanie, tak, let i const hoist, ale nie możesz uzyskać do nich dostępu przed rzeczywistą deklaracją jest oceniana w czasie wykonywania.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-22 14:50:57

ES6 wprowadza zmienne Let, które pojawiają się z block level scoping. Dopóki ES5 nie mieliśmy block level scoping, więc zmienne zadeklarowane wewnątrz bloku są zawsze hoisted do zakresu na poziomie funkcji.

Zasadniczo Scope odnosi się do tego, gdzie w programie są widoczne Twoje zmienne, co określa, gdzie możesz używać zadeklarowanych zmiennych. W ES5 mamy global scope,function scope and try/catch scope, z ES6 otrzymujemy również przeskalowanie poziomu bloku za pomocą Let.

  • gdy zdefiniujesz zmienną za pomocą słowa kluczowego var znana jest cała funkcja od momentu jej zdefiniowania.
  • Kiedy zdefiniujesz zmienną za pomocą instrukcji let jest ona znana tylko w bloku, który jest zdefiniowany.

     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"]);
    

Jeśli uruchomisz kod, zobaczysz, że zmienna {[15] } jest znana tylko w loop, a nie przed i po. Jednak nasza zmienna {[17] } jest znana w entire function od momentu jej zdefiniowania.

Jest jeszcze jedna wielka zaleta za pomocą let, ponieważ tworzy nowe środowisko leksykalne, a także wiąże świeżą wartość zamiast zachowywania starego odniesienia.

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

Pierwsza pętla for zawsze wypisuje ostatnią wartość, z let tworzy nowy zakres i binduje nowe wartości druk us 1, 2, 3, 4, 5.

Idąc do constants, Działa w zasadzie jak let, jedyna różnica polega na tym, że ich wartości nie można zmienić. W stałych mutacja jest dozwolona, ale zmiana przypisania nie jest dozwolona.

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

Jeśli stała odnosi się do object, zawsze będzie odnosić się do object, ale sama object może być zmieniona (jeśli jest zmienna). Jeśli chcesz mieć niezmienny object, możesz użyć 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-11 06:46:36