ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Javascript] Hoisting(호이스팅)이란?
    Front-end/Javascript 2020. 5. 4. 12:16
    반응형

    Hoisting이란?

    요즘 웹 개발하는 환경은 bolierplate를 쓰는 경우가 많다. 내장된 eslint와 같은 syntax 검사 모듈의 도움을 받기 때문에, 개발자는 var 대신 let, const를 쓰면서 hoisting의 개념을 알기 쉽지 않다. eslint가 엄격할 때는 성가실 때가 많지만 경고 또는 에러를 내주는 이유는 바로 hoisting 때문이지 않을까 생각이 된다. 

    Hoisting(호이 스팅)이란, 함수 또는 변수의 선언을 각각의 유효 범위의 최상단에 선언해주는 것을 말한다.

     - 유효 범위란 함수 블록{}을 말한다.

     - JS Parser가 유효 범위 내의 코드를 SSG 훑은 후, 이를 기억했다가 실행시킨다.

     - 함수와 변수의 선언초기화분리하는 과정이라고 생각할 수 있다.

     - 메모리 관점으로 보았을 때, 컴파일 단계에서의 위치와는 다르지 않다. 즉 코드가 옮겨지는 것은 아니다.


    변수 Hoisting

    Working case

    num = 6;
    num + 7;
    var num; 
    /* num이 선언되지 않더라도 에러를 내지 않습니다 */

    위의 코드를 실행했을 때 undefined 가 표시될 것 같지만, 놀랍게도 13이라는 결과가 나오게 된다. 

    /* After Hoisitng */
    var num;
    num = 6;
    num + 7;

    그 이유는 위에서 언급했던 Hoisting 때문이다. Hoisting의 과정에서 JS Parser가 기억해두고 실행시킨다고 했던 것처럼, var num(선언부)를 유효 범위의 최상부로 끌어올려 실행시키기 때문에, 에러가 생기지 않는다.

     

    Error case

    var x = 1; // x 초기화
    console.log(x + " " + y); // '1 undefined'
    var y = 2;
    

    하지만, 위와 같은 케이스는 어떻게 될까? 콘솔에 '1 undefined'가 표시 될 것이다.

    // Hoisiting 후.
    var x = 1; // x 초기화
    var y; // y 선언
    console.log(x + " " + y); // '1 undefined'
    y = 2; // y 초기화

    그 이유는 변수의 선언부만 hoist 되기 때문에, console.log를 실행하는 단계에서는 변수 y가 초기화되지 않았기 때문이다. 


    함수 Hoisting

    변수에 이어 함수 hoisting도 알아보도록 하자.

    Working case

    catName("Chloe");
    
    function catName(name) {
      console.log("My cat's name is " + name);
    }
    /*
    위 코드의 결과는: "My cat's name is Chloe"
    */
    

    위의 코드를 실행시키면 "My cat's name is Chloe"라고 콘솔에 나타날 것이다.

    function catName(name) {
      console.log("My cat's name is " + name);
    }
    
    catName("Chloe");
    /*
    위 코드의 결과는: "My cat's name is Chloe"
    */

    함수 또한, 변수처럼 선언부가 hoisiting 되면 위와 같이 코드가 실행되기 때문에, 에러 없이 정상 작동하게 된다.

     

    Error case

    catName("Chloe");
    
    var catName = function(name) {
      console.log("My cat's name is " + name);
    }
    /*
    위 코드의 결과는: "Uncaught TypeError: catName is not a function"
    */

    위의 코드를 실행시키게 되면 "Uncaught TypeError: catName is not a function"과 같은 에러를 표시한다.

    var catName;
    catName("Chloe");
    
    catName = function(name) {
      console.log("My cat's name is " + name);
    }

    그 이유는 앞서 언급했듯이 선언부만 최상으로 끌고 가기 때문에, 초기화되지 않은 catName("Chloe")는 에러가 난다.


    Hoisting 우선순위

    변수와 함수의 Hoisting의 각각 working case와 error case를 살펴보았다.

    변수와 함수가 같은 이름으로 선언하게 될 경우, 우선순위는 변수에 있다.

    var fruit = "Apple";
    
    function fruit() {
      console.log("Pear");
    }
    function vegetable() {
      console.log("Onion");
    }
    
    var vegetable = "Potato";
    
    console.log(typeof fruit);
    console.log(typeof vegetable);

    fruit의 타입은 String, vegetable의 타입은 function일 것 같지만 그렇지 않다.

    var fruit = "Apple";
    var vegetable;
    
    function fruit() {
      console.log("Pear");
    }
    function vegetable() {
      console.log("Onion");
    }
    
    vegetable = "Potato";
    
    console.log(typeof fruit);
    console.log(typeof vegetable);

    Hoisting 할 때, 변수가 함수보다 우선순위에 있기 때문에 , vegetable의 선언부가 위로 올라간다. 그 후, vegetable() 함수가 초기화되지만, 다시 vegetable = "Potato"가 다음 라인에서 다시 초기화된다. 따라서, 콘솔에서 fruit, vegetable 모두 String 타입을 보여주게 된다.


    Hoisting 그리고 es2015

    서두에서 언급했던 것처럼 요즘 개발 환경에서 eslint를 사용하게되면, 아래와 같은 에러를 자주 표시할 것이다.

    require let or const instead of var (no-var)

     

     

    node.js와 webpack 환경에서 ESLint가 종종 귀찮게 컴파일 에러를 표시할 때가 있는데, 그도 다 이유가 있었다.


    참고

    https://www.edwith.org/boostcourse-web/lecture/16695/

    https://yuddomack.tistory.com/entry/자바스크립트-호이스팅Hoisting#recentComments

    https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html

    https://eslint.org/docs/rules/no-var

    반응형

    댓글

Designed by Tistory.