let 또는 const로 선언 된 변수가 ES6에서 호이스트되지 않습니까?


266

나는 ES6을 잠시 가지고 놀았고 선언 된 변수가 var예상대로 게양되는 것을 알았습니다 ...

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

...로 선언 된 변수 let또는 const호이 스팅에 문제가있는 것 같습니다 :

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

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

이것은 선언 된 변수 let또는 const게양되지 않은 변수를 의미합니까 ? 여기서 무슨 일이 벌어지고 있습니까? 이 문제 let와 그 사이에 차이점 const이 있습니까?

답변:


346

@thefourtheye는 이러한 변수 가 선언되기 전에 액세스 할 수 없다고 말하는 것이 정확합니다 . 그러나 그것보다 조금 더 복잡합니다.

변수가 호이스트 let되거나 선언 const되지 않은 변수 입니까? 여기서 무슨 일이 벌어지고 있습니까?

모든 선언은 ( var, let, const, function, function*, class) "게양"하는 자바 스크립트. 즉, 이름이 범위에서 선언되면 해당 범위에서 식별자가 항상 해당 특정 변수를 참조합니다.

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

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

    let/const/… x;
}

기능 및 블록 범위 1 모두에 해당 됩니다.

의 차이 var/ function/ function*선언과 let/ const/ class선언은입니다 초기화 .
전자는 undefined바인딩의 맨 위에 바인딩이 생성 될 때 또는 (생성기) 기능 으로 초기화됩니다 . 그러나 사전에 선언 된 변수는 초기화되지 않은 상태로 유지 됩니다. 즉, ReferenceError액세스하려고하면 예외가 발생합니다. 때 만 초기화 얻을 것이다 let/ const/ class문이 평가되는 호출되는 (위)하기 전에, 모든 시간 데드 존을 .

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

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

공지는 것을 let y;문에 변수 초기화합니다 undefined같은 let y = undefined;것입니다.

시간적 데드 존은 구문론 위치, 오히려없는 시간 변수 (범위) 생성 및 초기화 사이. 코드가 실행되지 않는 한 선언 위의 코드에서 변수를 참조하는 것은 오류가 아닙니다 (예 : 함수 본문 또는 단순히 죽은 코드). 코드가 선언 아래에 있습니다 (예 : 너무 일찍 호출 된 함수 선언에서).

이 문제 let와 그 사이에 차이점 const이 있습니까?

아니오, 호이 스팅이 고려되는 한 동일하게 작동합니다. 그들 사이의 유일한 차이점은 const개미가 선언의 초기 부분에서만 할당되어야하고 할당 될 수 있다는 것입니다 ( const one = 1;, const one;같은 재 할당 one = 2은 유효하지 않습니다).

1 : var선언은 여전히 ​​함수 수준에서만 작동합니다.


16
나는 모든 선언이 일시적 데드 존으로 인해 명확하지 않기 때문에 모든 선언이 훨씬 더 잘 들린다는 것을 let foo = () => bar; let bar = 'bar'; foo();보여줍니다 .
Estus Flask

1
let 전에 선언 된 함수 (즉, 클로저)에서 let 정의를 참조하는 것에 대해 물었습니다. 이것이 질문에 대한 대답이라고 생각합니다. 합법적이지만 let 문을 실행하기 전에 함수를 호출하면 참조 오류가 발생하고 나중에 함수를 호출하면 괜찮습니다. 아마도 이것이 사실이라면 대답에 추가 될 수 있습니까?
Mike Lippert

2
@MikeLippert 네, 맞습니다. 변수가 초기화되기 전에 변수에 액세스하는 함수를 호출해서는 안됩니다. 이 시나리오는 예를 들어 모든 호이스트 함수 선언에서 발생합니다.
Bergi

1
만드는 결정 const처럼은 let설계 결함이다. 범위 내에서 const접근 할 때 호이스트되고 적시에 초기화되도록해야합니다. 실제로 는 "readonly"처럼 작동하는 변수를 만드는 const, a let및 다른 키워드가 있어야합니다 let.
Pacerier

1
" 전자는 정의되지 않은 상태로 초기화됩니다 …"는 var 선언에 대해서는 괜찮을 수 있지만 실행이 시작되기 전에 값이 할당 된 함수 선언에는 적합하지 않은 것 같습니다.
RobG

87

ECMAScript 6 (ECMAScript 2015) 사양 인용 letconst선언 섹션,

변수가 포함 된 Lexical Environment가 인스턴스화 될 때 변수가 작성되지만 변수의 LexicalBinding이 평가 될 때까지 어떤 방식으로도 액세스 할 수 없습니다 .

따라서, 귀하의 질문에, 네, 대답 letconst호이스트를하지만, 실제 선언이 런타임에 평가하기 전에 그들에 액세스 할 수 없습니다.


22

ES6Let와 함께 제공되는 변수를 소개 합니다 block level scoping. ES5우리가 가질 때까지 block level scoping, 블록 안에서 선언 된 변수는 항상 hoisted함수 레벨 범위에 있습니다.

기본적으로 Scope프로그램에서 변수가 보이는 위치를 나타내며 선언 한 변수를 사용할 수있는 위치를 결정합니다. 에 ES5우리가 global scope,function scope and try/catch scope와에게 ES6우리는 또한하자를 사용하여 블록 레벨 범위 지정을 얻는다.

  • var키워드 를 사용하여 변수를 정의하면 정의 된 순간부터 전체 함수로 알려져 있습니다.
  • let명령문 으로 변수를 정의하면 정의 된 블록에서만 알 수 있습니다.

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

코드를 실행하면 변수 jloop전후 에만 알려지지 않은 것을 알 수 있습니다 . 그러나 우리의 변수 ientire function앞으로 정의되는 순간부터 알려져 있습니다.

let을 사용 하면 새로운 어휘 환경을 만들고 오래된 참조를 유지하는 대신 새로운 가치를 결속시키는 또 다른 큰 이점이 있습니다 .

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

첫 번째 for루프는 항상 마지막 값을 인쇄 let하며 새로운 범위를 만들고 새로운 값을 인쇄하여 바인딩합니다 1, 2, 3, 4, 5.

에 와서 constants, 그것은 기본적으로처럼 작동 let하지만 유일한 차이점은 그들의 가치를 바꿀 수 없다는 것입니다. 상수에서는 돌연변이가 허용되지만 재 할당은 허용되지 않습니다.

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

상수가을 object참조하면 항상을 참조 object하지만 object자체가 변경 될 수 있습니다 (변경 가능한 경우). 불변성을 갖고 object싶다면Object.freeze([])


5

에서 MDN 웹 문서 :

ECMAScript를 2015 년에, let그리고 const게양하지만, 초기화되지 않습니다. 변수 선언 전에 블록에서 변수를 참조하면 변수가 블록 ReferenceError의 시작부터 선언이 처리 될 때까지 "임시 데드 존"에 있기 때문에 결과 가 나타납니다.

console.log(x); // ReferenceError
let x = 3;

0

es6에서 let 또는 const를 사용할 때 변수를 사용하기 전에 선언해야합니다. 예. 1 -

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

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

예. 2-

// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.