JavaScript

[JavaScript] Hoisting

Hoon1994 2020. 12. 9. 22:36

 

Javascript

 

✏️ Hoisting이란 무엇일까? 

 

흘러흘러, 코딩의 코자도 모르던 시절, 국비지원 학원을 통해 취업을 했지만, 속성으로 배우고 취업해서 그런지 

자바스크립트의 기본 원리에 대해서 잘 몰랐었다. 물론 시간이 지나면서 어느정도 알게 되었지만, 쓴이처럼 

잘 모르시는 분들이 계실 수도 있을까봐 포스팅해본다. (이미 많은 포스팅이 있는 건 안 비밀)

 

 

✏️변수의 호이스팅에 대해 알아보자.

 

우선 코드를 하나 보자. 

 

var a = 1;
console.log(a);

 

위의 콘솔은 어떤 결과를 리턴해줄까? 

답은 당연히 1이다. 

 

그렇다면 이번엔 어떨까.

console.log(a);
var a = 1;

 

변수를 선언하기 전에 변수를 호출해버렸다. 결과는 undefined...

undefined

 

다른 코드도 보자.

console.log(a);

 

이번에는 할당 조차 하지 않았다. 선언도 하지 않은 없는 변수를 호출한다. 결과는?

 

ReferenceError: a is not defined

 

정의되지 않았다는 에러가 나온다. 당연하다. 정의를 하지 않았으니까, 

하지만 선언하기 전에 호출했던 코드의 결과와 다른 점은 조금 의심해볼 필요가 있다.

 

그럼 const로 해보자.

    console.log(a);
    const a = 1;

 

결과는! Cannot access 'a' before initialization

 

초기화전에 a에 접근할 수 없다고 한다... let을 사용했을 때도 마찬가지로 결과가 다르다. 왜이럴까? 

 

var 같은 경우 호이스팅이 일어나서, 변수 선언부를 상단으로 끌어올리게 된다. 

코드로 한번 보자.

 

// 작성한 코드

console.log(a);
var a = 1;

// 호이스팅 된 코드

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

 

선언부를 상단으로 끌어올렸기 때문에, undefined가 출력된다. 

반대로, let과 const는 위의 에러 그대로 해석하면된다. 선언이 되어 있지 않다는 것. 

 

그러면 const와 let으로 선언한 변수는 호이스팅이 되지 않는다고 할 수 있을까? 

정답은 아니다. let과 const도 호이스팅이 된다.

 

ES6의 constlet은 TDZ(Temporal Dead Zone)의 영향을 받아 에러가 발생하게 되는 것이다.

선언이 일어나기 전까지 TDZ의 영향을 받게된다. (TDZ는, 선언 전에 변수에 접근하는 것을 금지한다.)

 

결론은, const, let은 호이스팅되어 최상단에서 선언되지만 초기화 및 할당은 선언문(코드를 쓴 줄)에서 

실행되고, 그 전에 접근을 하려 하면 TDZ의 영향을 받아 Reference Error가 발생하는 것이다.

 

 

✏️함수 선언문과 표현문의 호이스팅에 대해서 알아보자.

 

변수 호이스팅을 이해했다면, 함수 호이스팅도 쉽게 이해할 수 있다.

앞서 그랫듯 코드를 먼저 보자.

 

 

아래 코드는 함수 선언식이다.

myFunc();

function myFunc() {
	console.log('hello!');
}

 

함수를 정의하기 전에 호출을 해버렸다. 단순히 코드만 보자면 에러가 발생할 것 같지만 해당 코드는

정상적으로 실행이 되고, "hello!" 를 출력한다. 그렇다면, 함수 표현식으로 정의할 경우 어떻게 될까?

 

 

아래 코드는 함수 표현식이다.

func();

var func = function myFunc() {
	console.log('hello!');
}

결과는! func is not a function...

 

const,let도 같을까? 다르다. const,let은 위 변수 부분에서도 봤던 것 에러가 뜬다. 

Cannot access 'func' before initialization

 

첫 번째인 함수 선언문은 상단으로 호이스팅되어, 코드가 정상적으로 실행이 되고, 

두 번째인 함수 표현문은 에러가 출력되며 코드가 실행되지 않는다.

 

실행을 하지 않고 콘솔로 찍어보면, 조금 더 이해가 쉬울 것 같다.

 

// var    
    
    console.log(func);

    var func = function myFunc() {
      console.log('1');
    }
    
    결과: undefined
    
// const 

    console.log(func);

    const func = function myFunc() {
      console.log('1');
    }    
    
    결과: Reference Error

 

undefined가 뜨는 이유가 무엇일까? 초기화는 됐다는 것이다. var func은 선언 및 초기화가 되었기에 undefined가 출력이 되고, const func은 선언은 됐지만 TDZ로 인해 접근할 수 없어 Reference Error가 출력되는 것이다. 

 

테스트해보면서 공통적인 부분은, 선언부는 호이스팅 된다는 것이고, const,let도 호이스팅되지만 TDZ로 인해 접근할 수 없어 Refence Error 에러가 난다는 것. 

 

그러므로 호이스팅으로 인한 문제를 겪고 싶지 않다면 const,let을 사용하고, 

함수 표현식을 사용하면 되고, 반대로 호이스팅을 이용하고 싶다면 var 및 함수 선언문을 이용하면 될 것 같다.