ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] 자바스크립트 호이스팅(Hoisting) 가볍게 이해하기
    프로그래밍 이야기/JavaScript 공부 2020. 5. 28. 02:07

    호이스팅도 스코프와 마찬가지로 이를 좀 더 명확하게 이해하려면 scope의 깊은 개념과 자바스크립트의 실행 문맥을 이해한 상태에서 살펴보는 것이 좋지만, 그런 부분을 이해하기에는 생각보다 많은 배경지식들이 필요하다.

     

    하지만, 그냥 가볍게 호이스팅이 어떠한 현상인지 정도만 이해해도 코드를 작성하거나 다른 개념들을 이해하는 데에 생각보다 적잖이 도움이 되기에 이 포스트를 작성하게 되었다.

     

    호이스팅(Hoisting)이란?

    호이스트를 구글에 검색해보면, 위키백과에서 '호이스트는 로프 또는 체인이 감싸는 드럼 또는 리프트 휠을 사용하여 하중을 들어 올리거나 내리는 데 사용되는 장치입니다.'라고 알려준다.
    이와 비슷한 의미로 자바스크립트에서는 선언문을 끌어올리는 동작을 호이스팅(Hoisting)이라고 부른다.

     

    자바스크립트 프로그램이 실행되면 일반적으로 코드가 한 줄 한 줄 위에서부터 차례대로 해석될 것이라고 생각한다.

    대부분의 경우 맞는 말이지만, 간간히 예외들이 존재한다.

     

    다음 코드를 살펴보자.

    showDefault();
    
    function showDefault() {
        console.log('1일 3깡이 기본입니다.');
    }

     

    이 코드를 실행하면 1일 3깡이 기본입니다.가 출력이 되는데,

    분명히 함수를 선언하기 전에 함수를 호출했음에도 불구하고

    아무렇지 showDefault함수가 않게 실행이 되었다는 뜻이다.

     

    다시 말해

    function showDefault() {
        console.log('1일 3깡이 기본입니다.');
    }
    
    showDefault();

    마치 이렇게 작성한 코드와 동일하게 동작한다는 뜻인데,

    이렇게 함수 선언문이 끌어올려지면서 함수 선언이 호출 이전에 된 것처럼 동작하는 현상을 호이스팅이라고 한다.

     

    변수의 호이스팅

    호이스팅은 방금 이렇게 함수의 선언문도 호이스팅이 되고, 변수의 선언문도 호이스팅이 된다.

    단, var 키워드로 선언한 변수에 한해서 드러난다.

    console.log(name); // ReferenceError

    이렇게 콘솔에 name을 출력하면, ReferenceError가 발생한다. name이라는 변수가 선언된 적이 없기 때문이다.

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

    그런데 이렇게 name이 이후에 변수를 선언하게 되면, 놀랍게도 undefined라는 값을 출력한다.

     

    여기에 값을 할당하면 어떻게 될까?

    console.log(name); // undefined
    var name = 'Bigtop';

    이렇게 변수를 선언과 동시에 값을 초기화하면, Bigtop이 출력될 것 같지만, 아쉽게도 undefined가 출력된다. 위 코드의 두 번째 줄은 우리가 보기에는 한 줄로 작성되었지만, 사실 자바스크립트가 이 코드를 해석할 때는, 아래의 코드와 같이 해석을 한다.

    console.log(name); // undefined
    var name;
    name = 'Bigtop';

    호이스팅은 선언문에 한해서 이뤄지기 때문에 사실상 두 번째 줄의 선언부만 위로 끌어올려진 것이다.

    따라서 초기화 이후에 다시 name을 출력해보면 그제야 Bigtop이 출력되는 걸 확인할 수 있다.

    console.log(name); // undefined
    var name = 'Bigtop';
    console.log(name); // Bigtop

    같은 원리에 의해서 함수 표현식은, 호이스팅이 드러나지 않는다.

    showDefault();
    
    var showDefault = function() {
        console.log('1일 3깡이 기본입니다.');
    }

    다시 한번 언급하지만. 변수 선언의 호이스팅은 var 키워드에 한해서 드러난다. 깊이 따지자면 드러날 뿐이지, let과 const에서도 호이스팅이 일어나지 않는다고 할 수 없다. let과 const로 변수를 선언할 경우에는 ReferenceError를 출력하는데, 친절하게 선언 이전에 접근하지 말라는 안내를 해준다. 이로 인해 호이스팅이 뭔가 드러나지 않는 것처럼 느껴질 뿐, 실제로는 모든 선언문이 hoisting 된다.

    그렇지만 그런 자세하고 디테일한 부분까지 지금은 구분하지 말자. 언젠가 기회가 되면 let과 const의 hoisting에 대한 이야기도 다시 정리해볼 예정이다.

    console.log(name); // ReferenceError
    let name = 'Bigtop';

    정리하면, 호이스팅은 

    1. var키워드로 선언한 변수

    2. 함수 선언문

    이 두 가지에서 호이스팅이 드러난다.

     

    호이스팅의 scope

    호이스팅은 항상 최상단으로 올라가지 않는다. 호이스팅도 scope의 개념을 따르는데, 전역으로 선언한 선언문의 경우에는 전역 범위의 최상단으로 끌려 올라가지만, 지역범위의 경우에는 해당 범위 내의 최상단으로 끌려 올라간다. 그런데, 호이스팅의 대상인, 함수와, var키워드는 모두 블록scope가 아니라 함수scope 이기 때문에 호이스팅의 scope는 다시,

    1. 전역 scope

    2. 함수 scope

    이렇게 둘로 나뉘게 된다.

    console.log(myName);
    showBigtop();
    showName();
    
    function showName() {
        console.log(myName);
        var myName = 'bigtop';
        
        showBigtop();
        function showBigtop() {
        	console.log(myName);
        }
    }

    위 코드를 천천히 살펴보면, 일단 위 상태 그대로 코드를 실행했을 때 1번 줄에서부터 Error가 발생해서 더 이상 코드가 동작하지 않는다. myName은 showName의 함수의 최상단으로 호이스팅 될 뿐, 전역범위로 호이스팅 되지 않았기 때문이다.

     

    만약 1번 줄을 주석 처리하고 코드를 실행시키면 이번엔 2번 줄에서 Error가 발생하는데,
    마찬가지로 showBigtop함수도 showName 함수의 최상단으로 호이스팅 되었기 때문에, showName함수 밖에서는 호출될 수 없다.

     

    그렇게 2번 줄도 주석 처리하고 코드를 실행시키게 되면, 3번 줄의 showName 함수 호출은 5번 줄 이하의 선언문이 호이스팅되어 정상적으로 호출된다.

     

    그러면 6번 줄의 myName을 콘솔에 출력하는 동작은 7번 줄의 변수 선언문이 호이스팅되어 undefined가 출력이 되고,

     

    9번 줄의 showBigtop함수 호출은 10번 줄 이하의 함수 선언문이 호이스팅되어 정상적으로 잘 출력이 된다. 


    함수 호출의 위치가 bigtop이라는 문자열을 할당한 이후에 호출되었기 때문에

    9번 줄에서 함수를 호출한 결과로 콘솔에는 'bigtop'이 출력된다.

     

    만일 myName변수에 값을 할당하기 전에 showbigtop함수를 호출했다면 undefined가 출력이 되었을 것이다.

     

    마무리

    마지막 scope 부분은 다소 조잡하게(?) 설명하긴 했지만, 아무튼 이번 포스트는 호이스팅에 대해서 가볍게 정리를 해봤다.

     

    자바스크립트에서 이렇게 선언문의 위치가 움직이는 듯한 현상이 코드를 읽고 이해하는 입장에서 다소 혼란스러울 수도 있다. 그래서 과거에는 호이스팅을 방지하기 위해서 선언 부분을 의도적으로 상단에 작성하기를 권장하곤 했었는데, const, let 키워드가 등장하고 또 화살표 함수가 등장하면서, 그러한 권장사항들이 불가피한 필수사항이 되어버려서 사실상 이제는 호이스팅의 개념을 접하는 게 오히려 더 어려운 상황이 되어버리긴 했다.

     

    그럼에도 불구하고 자바스크립트의 하나의 개념으로써 자바스크립트 코드의 동작을 이해하는 데에 분명히 도움이 될 것이라 믿는다.

     

    특히나, var 변수를 사용할 일은 거의 없을지는 몰라도 함수 선언문은 여전히 쓰임이 있으니 호이스팅의 개념을 모르는 것보다는 이렇게 가볍게라도 정리해 두는 것이 바람직하지 않나(?) 생각된다.

     

    댓글

Designed by BigTop.