ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JS/호이스팅] Interpreted Language인 자바스크립트의 호이스팅(Hoisting)에 대하여
    Frontend 2019. 5. 3. 13:16

    자바스크립트, 인터프리터 언어(Interpreted Language)

    보통 우리가 사용하는 프로그래밍 언어는 고급 언어(High Level Language), 컴파일러 언어라고도 한다. 즉, 기계가 이해할 수 있는 0과 1로 표현된 2진수 언어가 아니라 인간이 이해하기 쉬운 자연어와 비슷한 구조를 갖는 언어를 말한다. 이러한 고급 언어를 사용하여 프로그래밍을 하면 반드시 기계어로 번역하는 과정을 필수적으로 거쳐야 하는데, 그 과정에서 사용되는 번역기에는 두 종류가 있다. 바로 컴파일러와 인터프리터이다.

     

    컴파일러를 사용하는 고급 언어를 우리는 Compiled Language라고 한다. 대표적인 Compiled Language에는 C언어가 있다. 컴파일러를 사용하면 프로그램 전체를 목적 프로그램으로 번역한 후 링킹(Linking)작업을 통해 컴퓨터에서 실행 가능한 실행 프로그램을 생성한다. 쉽게 풀이하면 프로그램 전체를 한 번에 쭉 번역한 후 실행 프로그램을 따로 생성한다는 뜻이다. 한 번에 프로그램 전체를 번역해야하니까 번역 속도는 느리다. 그러나 한 번 번역을 끝낸 후에는 이미 생성된 실행 프로그램만 실행하면 되니까 다시 번역을 할 필요가 없어져 실행 속도는 빨라진다.

     

    반면에 인터프리터는 프로그램을 한 줄 단위로 받아들여 번역하고 번역과 동시에 프로그램을 한 줄 단위로 즉시 실행한다. 그렇기 때문에 따로 목적 프로그램이 생성되지 않는다. 줄 단위로 번역하여 실행하기 때문에 번역 속도도 빨라진다. 그렇지만 프로그램을 매번 실행할 때마다 번역을 해야하기 때문에 실행 속도는 느려지고 CPU 사용 시간의 낭비가 커진다는 단점은 있다. 인터프리터를 사용하는 고급 언어를 우리는 Interpreted Language라고 한다.

     

    내가 지금 공부하고 있는 자바스크립트도 Interpreted Language이다. 우리가 js파일에 var a = 10; console.log(a);를 쓰고 실행시키면 한 줄 단위로 바로 실행되어 콘솔창에는 10이라는 값이 출력된다. 자바스크립트는 이렇게 한 줄 한 줄 실행하고 번역하기 때문에 따로 전처리 과정을 필요로하지 않는다.

     

    구분 컴파일러 인터프리터
    번역 단위 전체 행(줄)
    목적 프로그램 생성함 생성하지 않음
    실행 속도 빠름 느림
    번역 속도 느림 빠름
    관련 언어 FORTRAN, COBOL, C, ALGOL 등 BASIC, LISP, APL, SNOBOL 등

     


    자바스크립트의 호이스팅(Hoisting)

    한 줄 단위로 번역과 동시에 실행이 이루어지는 자바스크립트도 약간의 전처리 과정을 거칠 때가 있는 데 그 대표적인 예가 호이스팅(Hoisting)이다.

     

    Hoisting이라는 단어의 의미를 찾아보면 "raise (something) by means of ropes and pulleys."라고 나온다. 무언가를 끌어올린다는 뜻이다. 자바스크립트에서 호이스팅은 변수의 선언을 그 변수가 선언된 스코프(scope) 내에서 가장 최상단으로 끌어올린다는 뜻이다. 

     

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

    위의 코드를 살펴보자.

     

    만약에 자바스크립트에 호이스팅이 없다면 맨 첫번째 줄에서 에러(a is not defined)가 날 것이다. 왜냐하면 a를 선언하기도 전에 console.log(a)를 실행했기 때문이다. 그러나 호이스팅 때문에 위 구문은 에러가 나지 않는다. 

    변수 a의 선언이 호이스팅되어 스코프 가장 최상단으로 끌어올려지고, 첫번째 줄에서 아직 a의 값이 할당되지 않았기 때문에 undefined가 출력된다. 이것은 마치 아래의 코드처럼 작동하는 것과 같다.

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

     

    좀 더 자세하게 이 호이스팅 과정을 설명해보면 다음과 같다.

     

    자바스크립트로 작성한 프로그램을 실행시키면 약간의 전처리과정을 가지는데, 이것을 스캐닝 과정이라고 한다. 스캐닝 과정이 끝나고 다시 위에서부터 한 줄씩 차례로 코드를 실행시키는 것을 런타임 과정이라고 한다.

     

    console.log(a);	//undefined
    var a = 10;
    function b() {
      var a = 20;
      console.log(a);	//20
      console.log(c);	//undefined
      var c = 30;
      console.log(c);	//30
      console.log(d);	// undefined
    }
    b();
    console.log(a);	//10
    var d;

    위 코드의 실행과정은 다음과 같다.

     

    • 1차 스캐닝 과정에서 전역 변수 a와 d의 선언, 그리고 함수 b가 메모리에 등록된다. (a와 d는 선언만 되었으므로 값은 아직 할당되지않은 undefined상태이다. b는 함수로 인지되어 등록된다.)
    • 1차 스캐닝 후 위에서부터 차례로 코드를 읽는다. (이를 런타임 과정이라고 한다.)
    • 스캐닝 과정에서 a의 선언이 등록되었으나 a의 값은 아직 할당되지 않았으므로 첫번째 줄에서 undefined가 출력된다.
    • 두번째 줄에서 a의 값이 10으로 할당되었다.
    • 11번째 줄에서 함수 b가 호출되었다.
    • 함수 b 스코프 내에서 다시 스캐닝 과정을 거친다. 변수 a와 c의 선언을 메모리에 등록한다.
    • 스캐닝 후 다시 b스코프의 첫번째 줄(위 코드의 4번째 줄)부터 읽으며 런타임 과정을 갖는다.
    • 4번째 줄에서 a에 20이란 값이 할당되었으므로 5번째 줄에서 20이 출력된다.
    • 6번째 줄에서 c는 undefined가 출력된다. (스캐닝 때 c의 선언이 등록되었으므로)
    • c에 30이란 값이 할당되었으므로 8번째 줄에서 30이 출력된다.
    • 9번째 줄에서 d란 값을 출력하려고 하는데, b함수 스코프 내에 변수 d가 존재하지 않기 때문에 부모 스코프에서 변수 d를 찾는다. 아까 d 변수의 선언이 1차 스캐닝 때 등록되었으므로 undefined를 출력한다.
    • 함수호출 종료 후 12번째 줄에서 a는 10을 출력한다. b함수 스코프 내의 a변수는 b함수 스코프 내에서만 접근할 수 있기 때문에 영향을 받지 않는다.

     


    함수선언식(Function Declaration)과 함수표현식(Function Expression)

    자바스크립트의 호이스팅은 변수에만 적용되는 것이 아니라 함수에도 적용된다. 즉, 함수가 선언되면 그 함수 자체가 해당 스코프 최상단으로 끌어올려진다. 다만, 함수 호이스팅은 함수의 작성법에 의해 다르게 적용된다.

     

    함수선언식(Function Declaration)은 다음과 같이 작성되는 함수를 말한다.

    function foo () {
    
    }

    위와 같은 형태의 함수는 함수 자체가 호이스팅되기 때문에 스코프 어디에서든 함수 호출이 가능하다.

     

    foo();
    function foo () {
    	console.log('hello');
    }
    foo();

    즉, 위와 같은 코드를 보면 foo함수의 선언은 두 번째 줄에서 했지만 첫 번째 줄에서도, 5번째 줄에서도 foo함수를 실행할 수 있다.

     

     

    반면, 함수표현식(Function Expression)은 다음과 같이 작성되는 함수를 말한다.

    var bar = function() {
    
    }

    함수의 이름이 변수처럼 선언되고 함수가 작성되는 방식이다.

    이 경우에는 변수의 호이스팅처럼 변수의 선언만 undefined인 상태로 최상단으로 끌어올려진다.

     

    그렇기 때문에 bar변수에 함수를 할당하기 전에 bar함수를 실행하면 (bar is not a function)이라는 에러가 뜬다. bar변수에 함수를 할당하기 전에 bar변수는 undefined이고 undefined는 에러메시지 그대로 함수가 아니기 때문이다. 

     

    bar();	// 에러 출력(bar is not a function)
    var bar = function() {
    	console.log('Hello');
    }
    bar();

     

     

     

     

    반응형

    COMMENT