본문 바로가기
Language/JavaScript

[JavaScript] 호이스팅 (Hoisting)

by J4J 2021. 6. 14.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 호이스팅에 대해 적어보는 시간을 가져보려고 합니다.

 

 

호이스팅이란?

 

호이스팅이라고 하는 것은 선언된 변수들을 최상단으로 끌어올려주는 것을 의미합니다.

 

예를 들어 다음과 같은 코드가 있다고 가정하겠습니다.

 

<script>
    console.log(a);
    var a = 3;
</script>

 

 

일반적인 상황에서 해당 코드를 해석해보면 a라는 변수가 선언된 위치에 도달하기 전에 a변수를 사용했기 때문에 에러가 발생될 것이라고 생각을 할 수 있습니다.

 

하지만 해당 코드는 호이스팅에 의해 에러가 나지 않습니다.

 

왜냐하면 호이스팅이 되어 자바스크립트가 인식하는 실제 코드는 다음과 같기 때문입니다.

 

<script>
    var a;
    console.log(a);
    a = 3;
</script>

 

 

참고적으로 위의 코드는 a변수를 출력했을 때 3이라는 값이 나오지 않고 undefined라는 값이 나오게 됩니다.

 

그리고 이렇게 변수 선언 위치를 최상단으로 끌어올려주는 것을 호이스팅이라고 합니다.

 

 

호이스팅은 크게 2가지로 나눌 수 있습니다.

 

  • 변수 호이스팅
  • 함수 호이스팅

 

 

변수 호이스팅

 

변수 호이스팅은 말 그대로 변수로 사용되는 키워드들과 관련된 것입니다.

 

변수로 사용되는 대표적인 키워드들은 var, let, const가 있습니다.

 

하지만 이들 중에서도 차이점이 존재하는데 var는 함수 단위를 기준으로 호이스팅이 발생되고 let, const는 블럭 단위를 기준으로 호이스팅이 발생됩니다.

 

우선 var에 대해 말씀드리겠습니다.

 

var는 함수 단위를 기준으로 호이스팅이 발생된다고 했는데 단순하게 var변수가 선언된 위치를 기준으로 가장 가까운 상위 함수까지 호이스팅이 된다는 것입니다.

 

예를 들어 다음과 같은 코드가 있다고 가정해보겠습니다.

 

<script>
    function funcA() {
        console.log(a);

        if(1 === 1) {
            var a = 3;
            console.log(a);
        }
    }

    funcA();
</script>

 

 

해당 코드를 실행하면 결과는 다음과 같습니다.

 

<script>
    function funcA() {
        console.log(a); // undefined

        if(1 === 1) {
            var a = 3;
            console.log(a); // 3
        }
    }

    funcA();
</script>

 

 

반응형

 

 

위와 같은 결과가 나오는 이유는 말씀드린 대로 var는 함수 단위를 기준으로 호이스팅이 되기 때문입니다.

 

실제로 자바스크립트가 위의 코드를 해석할 때 다음 코드와 동일하게 해석합니다.

 

<script>
    function funcA() {
        var a; // a변수 호이스팅!
        
        console.log(a); // undefined

        if(1 === 1) {
            a = 3;
            console.log(a); // 3
        }
    }

    funcA();
</script>

 

 

하지만 let과 const는 함수 단위가 아닌 블럭 단위를 기준으로 호이스팅이 되기 때문에 위와 다른 결과가 나옵니다.

 

여기서 말하는 블럭 단위는 중괄호( { } )로 나누어지는 구역들을 블럭이라고 부릅니다.

 

위의 코드에서 var대신 let을 사용해보겠습니다.

 

<script>
    function funcA() {
        console.log(a);

        if(1 === 1) {
            let a = 3;
            console.log(a);
        }
    }

    funcA();
</script>

 

 

위의 코드를 실행하면 다음과 같은 결과가 나옵니다.

 

<script>
    function funcA() {
        console.log(a); // Uncaught ReferenceError: a is not defined

        if(1 === 1) {
            let a = 3;
            console.log(a);
        }
    }

    funcA();
</script>

 

 

 

왜 에러가 발생될까요?

 

왜냐하면 let은 블럭단위를 기준으로 호이스팅 되기 때문에 자바스크립트는 위의 코드를 다음 코드와 동일하게 해석합니다.

 

<script>
    function funcA() {
        console.log(a); // Uncaught ReferenceError: a is not defined

        if(1 === 1) {
            let a; // a변수 호이스팅
            a = 3;
            console.log(a);
        }
    }

    funcA();
</script>

 

 

a라는 변수가 메모리에 적재되기 전에 a변수를 사용하는 코드가 존재하기 때문에 참조 에러가 발생되는 것입니다.

 

 

그리고 추가적으로 아무리 호이스팅이 되었다고 하더라도 실제 변수 선언을 한 곳까지 도달하지 않을 경우 메모리에 데이터가 적재되지 않았기 때문에 제대로 된 데이터들을 확인할 수 없습니다.

 

여기서도 var와 let, const의 차이가 존재하는데 var는 실제 선언 위치에 도달하기 이전에 사용되면 undefined가 출력되지만 let, const는 에러가 발생됩니다.

 

여기서 let, const의 에러가 발생되는 이유가 TDZ(Temporally Dead Zone)의 영향이라고도 일컫는데 데이터가 실제 적재되기 전까지 let, const들은 TDZ에 있다고 부릅니다.

 

<script>
    function funcA() {
        console.log(a); // undefined
        console.log(b); // Uncaught ReferenceError: Cannot access 'b' before initialization, b는 아직 TDZ에 있기 때문

        var a = 3;
        let b = 4;
    }

    funcA();
</script>

 

 

728x90

 

 

함수 호이스팅

 

자바스크립트에서 함수는 크게 함수 표현식, 함수 선언식으로 나눌 수 있습니다.

 

함수 표현식은 다음과 같이 함수를 정의할 때 자바스크립트 변수에 저장하는 것을 함수 표현식이라고 합니다.

 

<script>
    const funcA = function() {
        console.log('funcA!!');
    }
</script>

 

 

함수 선언식은 다음과 같이 자바스크립트 변수에 저장하지 않고 function키워드 옆에 함수 이름을 지정하는 것을 함수 선언식이라고 합니다.

 

<script>
    function funcA() {
        console.log('funcA!!');
    }
</script>

 

 

이렇게 함수 표현식과 선언식에서도 호이스팅에 의한 차이가 존재합니다.

 

먼저 함수 표현식에 대해 말씀드리겠습니다.

 

함수 표현식을 사용하여 다음과 같은 코드를 만들었다고 가정해보겠습니다.

 

<script>
    funcA();
    
    let funcA = function() {
        console.log('funcA!!');
    }
</script>

 

 

해당 코드는 어떻게 실행될까요?

 

실행하면 다음과 같은 결과가 나옵니다.

 

<script>
    funcA(); // Uncaught ReferenceError: Cannot access 'funcA' before initialization

    let funcA = function() {
        console.log('funcA!!');
    }
</script>

 

 

에러가 나오는 이유는 자바스크립트는 위의 코드를 다음과 같이 해석하기 때문입니다.

 

<script>
    let funcA; // funcA 호이스팅!

    funcA(); // Uncaught ReferenceError: Cannot access 'funcA' before initialization

    funcA = function() {
        console.log('funcA!!');
    }
</script>

 

 

위에서 funcA라는 함수가 실행될 때는 funcA는 함수가 정의된 상황이 아니기 때문에 에러가 발생되는 것이고 let뿐만 아니라 var, const를 사용해도 동일한 이유로 동일한 결과가 나오게 됩니다.

 

 

위의 코드를 함수 선언식으로 변경해보겠습니다.

 

<script>
    funcA();

    function funcA() {
        console.log('funcA!!');
    }
</script>

 

 

해당 코드를 실행하면 다음과 같은 결과가 나옵니다.

 

<script>
    funcA(); // funcA!!

    function funcA() {
        console.log('funcA!!');
    }
</script>

 

 

선언식 같은 경우는 정상적으로 실행되었는데 그 이유는 funcA함수가 호이스팅되어 자바스크립트가 다음과 동일하게 코드를 해석하기 때문입니다.

 

<script>
    function funcA() {
        console.log('funcA!!');
    }

    funcA(); // funcA!!
</script>

 

 

다만 함수 선언식도 블럭 단위를 기준으로 호이스팅이 되기 때문에 다음과 같은 경우는 에러가 발생하게 됩니다.

 

<script>
    funcA(); // Uncaught TypeError: funcA is not a function

    if(1 === 1) {
        function funcA() {
            console.log('funcA!!');
        }
    }
</script>

 

 

 

 

 

이상으로 호이스팅에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

728x90
반응형

댓글