본문 바로가기

Programming/Javascript

11. Javascript 실행 컨텍스트(3) - 코드 실행과 함수 호이스팅

javascript logo image

 

 

자, 앞에서 예제 코드의 실행 컨텍스트 생성 과정을 하나씩 살펴보았습니다. 이제 이 코드가 실행되는 구체적인 프로세스를 확인해 보겠습니다. 

 

function execute(param1, param2){
    var a = 1;
    var b = 2;
    function func(){
        return a + b;
    }

    return param1 + param2 + func();
}

execute(3, 4);

 

위의 코드 실행을 통해, 실행 컨텍스트의 변수 객체가 생성이 완료되면 아래 그림과 같은 구조를 형성하게 됩니다. 이미 설명했던 내용이지만, 현 단계에서 초기화는 이루어지지 않은 상태입니다. 

이렇게 변수 객체가 만들어지고 나서, 본격적으로 표현식의 실행이 시작됩니다. 변수 객체의 생성 과정에서는 변수 a, b의 존재만 선언되었고 값은 할당하지 않은 상태가 되는 것이죠. 여기서 한 가지 짚고 넘어가야 할 부분이 있습니다. 바로 함수 호이스팅 현상인데요, 방금 우리는 '변수 객체가 생성되고 난 후 [표현식]이 실행된다'라고 했습니다. 변수들이 값이 없는 상태로 선언되고 나서 할당이 이루어 지는 순서라고 볼 수 있죠. 이를 통해서 기본적으로 정의되지 않은 변수나 함수를 순서와 상관없이 실행하는 것이 불가능하다는 것을 알 수 있습니다. 

 

그런데 execute( )처럼 함수를 표현식이 아니라 일반 선언문 형태로 선언한다면 어떻게 될까요? 간단히 말하자면 '표현식'이 아니기 때문에 별다른 절차 없이 바로 함수 선언문의 코드까지 생성이 됩니다. 함수 호이스팅은 여기서 문제가 발생합니다. 다른 변수들은 변수 명만 선언되어 있는 상태이고, 값은 아직 할당되지 않은 상태이니까요. 여기서는 execute( )라는 함수 선언문 작성 이후에 마지막에 execute(3, 4)라는 형태로 함수를 실행했는데, 사실 이 순서를 무시하고 execute(3, 4)를 제일 코드 윗줄에 작성해도 실행은 된다는 의미입니다. 물론, 이는 프로그래밍 언어 전반적으로 올바른 순서가 아닙니다. 그렇기에 Javascript에서는 함수를 선언할 때 표현식을 쓰는 것을 권장하게 되는 것이죠. 

 

함수 호이스팅과 관련된 예제를 하나 더 살펴보겠습니다. 

 

foo();
bar();

var foo = function() {
    console.log("foo and x = " + x);
}

function bar() {
    console.log("bar and x = " + x);
}

var x = 1;

 

아마 어느 정도 프로그래밍에 익숙하신 분들이라면, 절대 위와 같은 방식으로는 코드를 작성하지 않으실 겁니다. 하지만, 정확히 저 순서대로 코드를 작성하고 실행한다면 어떤 일이 벌어질까요? 

 

우선, TypeError가 발생하게 됩니다. 그런데, 여기서 중요한 것은 '왜' TypeError가 발생하였는지입니다. 콘솔을 살펴보게 되면 [TypeError: foo is not a function] 라는 메시지가 출력됩니다. 즉, foo라는 함수를 코드 첫 줄에 실행을 해버렸는데 foo( )라는 함수가 선언되지도 않은 상태이기 때문에 발생하는 에러입니다. 아마 여기까지는 당연한 결과라고 생각하실 겁니다. 

 

그럼 이제 foo( ); 라는 함수를 각주로 처리하고 다시 한번 실행해 보도록 합시다. 이번에는 어떤 결과가 나올지 한 번 예상해 봅시다. 

 

// foo();
bar();

var foo = function() {
    console.log("foo and x = " + x);
}

function bar() {
    console.log("bar and x = " + x);
}

var x = 1;

 

콘솔의 결과를 확인하기 전에 답을 예상해 보셨나요? [bar and x = undefined] 라는 의외의 결과가 출력됩니다. 위에서 설명했듯이, 여기서 bar( )라는 함수는 함수 표현식이 아니라 선언문 형태로 작성되었습니다. 그렇기 때문에 전역 컨텍스트의 변수 객체 생성과정에서 x라는 변수에 1이 할당되기 이전에 실행이 되어버린 것입니다. 이 때는 x는 변수 명은 선언되었지만 값이 할당되지 않은 상태라 undefined 상태이고, 그래서 undefined가 그대로 출력된 것입니다. 

 

일반적으로 프로그래밍 언어를 사용하시는 분들은 기본적으로 함수나 변수를 선언한 다음 사용한다는 것을 기본 원칙으로 생각하고 있습니다. 그래서 혼란스러운 일이 발생할 가능성은 많지 않습니다. 다만, 함수 호이스팅을 통해 실행 컨텍스트 내에서 변수 객체가 어떤 과정을 통해 생성되는지 더 쉽게 이해하기 위해 설명한 내용이니, 변수 객체에서의 함수와 변수 초기화는 변수 객체가 모두 생성된 이후라는 점에 집중하시기 바랍니다.