Czy zmienne deklarowane są za pomocą let czy const?

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: Aditya Patnaik, 2015-07-04

6 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

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

 100
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
2018-12-12 16:34:03

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([])

 27
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

From MDN web docs:

W ECMAScript 2015, let i const są podnoszone, ale nie inicjowane. Odwołanie się do zmiennej w bloku przed deklaracją zmiennej skutkuje ReferenceError, ponieważ zmienna znajduje się w" martwej strefie czasowej " od początku bloku do przetworzenia deklaracji.

console.log(x); // ReferenceError
let x = 3;
 5
Author: YourAboutMeIsBlank,
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
2019-07-24 00:53:47

Zgodnie z ECMAScript® 2021

Let i Const

  • niech i deklaracje const definiują zmienne, które są ograniczone do środowiska leksykalnego kontekstu uruchamiania.
  • zmienne są tworzone, gdy ich zawierający rekord środowiskowy jest tworzony, ale nie mogą być dostępne w żaden sposób, dopóki nie zostanie ocenione Leksykalbinding zmiennej.
  • zmiennej zdefiniowanej przez Leksykalbinding z Inicjalizatorem przypisuje się wartość Inicjalizatora AssignmentExpression podczas oceny Leksykalbinding, nie podczas tworzenia zmiennej .
  • Jeśli Leksykalbinding w deklaracji let nie ma Inicjalizatora, zmiennej zostanie przypisana wartość undefined podczas oceny Leksykalbinding .

Instancjacja Deklaracji Blokowej

  • gdy blok lub CaseBlock jest oceniany, tworzony jest nowy deklaratywny rekord środowiska i powiązania dla każdej zmiennej o zasięgu bloku, stałej, funkcji, Klasa or zadeklarowana w bloku jest tworzona w rekordzie środowiska.
  • bez względu na to, jak kontrola opuszcza blok, środowisko leksykalne jest zawsze przywracane do poprzedniego stanu.

Top Level Leksykalnie Deklarowane Nazwy

Na najwyższym poziomie funkcji lub skryptu deklaracje funkcji są traktowane jak deklaracje var, a nie jak deklaracje leksykalne.

Podsumowanie

  • niech i const są podnoszone, ale nie zainicjowany.

    Odwołanie się do zmiennej w bloku przed deklaracją zmiennej powoduje ReferenceError, ponieważ zmienna znajduje się w" martwej strefie czasowej " od początku bloku do przetworzenia deklaracji.

Przykłady poniżej wyjaśniają, jak zmienne" niech " zachowują się w zakresie leksykalnym/zagnieżdżonym-leksykalnym.

Przykład 1

var a;
console.log(a); //undefined

console.log(b); //undefined
var b;


let x;
console.log(x); //undefined

console.log(y); // Uncaught ReferenceError: y is not defined
let y; 

Zmienna " y " daje referenceError, co nie znaczy, że nie jest podniesiony. Zmienna jest tworzona podczas tworzenia instancji środowiska zawierającego. Ale może nie być dostępny bcz, ponieważ znajduje się w niedostępnej "martwej strefie czasowej".

Przykład 2

let mylet = 'my value';
 
(function() {
  //let mylet;
  console.log(mylet); // "my value"
  mylet = 'local value';
})();

Przykład 3

let mylet = 'my value';
 
(function() {
  let mylet;   
  console.log(mylet); // undefined
  mylet = 'local value';
})();

W przykładzie 3 świeżo zadeklarowana zmienna "mylet" wewnątrz funkcji nie posiada Inicjalizatora przed instrukcją log, stąd wartość "undefined".

Źródło

ECMA MDN

 4
Author: Aditya Patnaik,
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
2020-07-03 12:33:39

W es6 kiedy używamy let lub const musimy zadeklarować zmienną przed ich użyciem. np. 1 -

// this will work
u = 10;
var u;

// this will give an error 
k = 10;
let k;  // ReferenceError: Cannot access 'k' before initialization.

Np. 2-

// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9
 1
Author: user260778,
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
2020-05-31 19:33:45