✍ 공부하기 | 자바스크립트 Closure(클로저), Hoisting(호이스팅)

    반응형

    오늘은 자바스크립트의 완전한 이론 부분이지 않을까 싶은데요

    자바스크립트를 그렇게 열심히 썼으면서... 이런 단어들은 처음 들어봤습니다 하하^^....

    면접 준비하면서 이렇게 기본 지식들을 쌓아올리게 되니 기분이 좋네요

    정말 중요한 이론이라고 생각합니다 (실은 저희가 다 이런 흐름으로 코드를 작성하고 있었죠)

     

     


     

     

    1. 자바스크립트 Closure(클로저)란?

    클로저는 독립적인 (자유) 변수를 가리키는 함수이다. 또는, 클로저 안에 정의된 함수는 만들어진 환경을 기억한다
    출처:MDN

     

    자바스크립트는 함수 안에서도 함수를 선언 할 수 있습니다. 전자를 외부함수라 정의하고 후자를 내부함수라 정의해보면, 기본적으로 내부함수는 외부함수의 요소에 접근이 가능합니다. 외부함수에서 그 함수의 수명이 다 하여 외부함수가 종료된 후에도 외부함수의 변수에 내부함수가 접근할 수 있는 메커니즘을 클로저라고 합니다.
    출처:blex.me/@yoyounn18

    음.. 저는 자바스크립트를 쓰면서 클로저라고 지칭하는게 당연한 흐름이라고 생각을 했습니다

    하지만 자바스크립트에서는 클로저에 대한 정의가 없다고 하더군요 (언어 명세에 없다고 합니다)

    클로저를 더 깊이 있게 이해하려면 스코프에대해 깊이 알아야하는데,

    스코프까지 이야기하면 너무 길어질 것 같아서 클로저의 예를 들어 이해해봅시다!

    • 클로저의 올바른 예시

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let color = "red";
     
    function foo() {
        let color = "blue";
        function bar() {
            console.log(color);
        }
        return bar;   //결과값 blue
    }
     
    const baz = foo();
    baz();  //결과값 blue
    cs

    출처:meetup.toast.com/posts/86

    어찌보면 당연하다고 생각하는 이 흐름이 클로저라고 불리더라고요

    근데 여기에 자세히 얽힌 스코프에대해 이야기하면.. 저도 완벽히 이해를 못했으니 넘어가고 하하

    일단 여기서 bar(=baz)와 같은 함수를 클로저라고 부릅니다

    그럼 클로저가 아닌 예를 볼까요?

    • 클로저의 틀린 예시

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function foo(){
        const color = "blue";
        function bar() {
            console.log(color);
        }
        bar();
    }
     
    foo();
    cs

    출처:meetup.toast.com/posts/86

    위 예시와 크게 차이가 없는 것 같아 보이지만, 여기서의 bar는 클로저가 아니라고 합니다

    bar는 foo안에서 정의되고 실행되었을 뿐, foo 밖으로 나오지 않았기 때문에 클로저라고 부르지 않습니다

    이렇게 보니 뭔가 어렵군요 😅

    👉 클로저는 환경을 기억하기 위해 메모리가 소모됩니다. 그래서 꼭 클로저 사용이 끝나면 참조를 제거하는 것이 좋습니다

    ex) baz = null;

     

     

     

     

    2. 자바스크립트 Hoisting(호이스팅)이란?

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

    함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말합니다

    1. 자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언합니다
    2. 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어 올리는 것입니다 (실제로 끌어 올려지는건 아님, 메모리에 변화 없음)
    • 호이스팅의 대상

    var 변수 선언과 함수선언문에서만 호이스팅이 일어납니다 (할당은 끌어 올려지지 않음) 

    let/const 변수 선언과 함수 표현식에서는 호이스팅이 발생하지 않습니다

    예시를 볼까요?

    • var변수와 let/const 변수
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    console.log("hello");
    var myName = "kyung";
    let mvName2 = "kyung2";
     
    // JS Parser 내부의 호이스팅의 결과. 위랑 같은 말임
     
    var myName; //호이스팅 선언
    console.log("hello");
    myName = "kyung";  // 할당
    let myName2 = "kyung2";  //호이스팅 발생 X
    cs

     

    • 함수선언문과 함수표현식
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    foo();
    foo2();
     
     
    // 함수선언문
    function foo() {
        console.log("안녕");
    }
     
    // 함수표현식
    var foo2 = function() {
        console.log("하이루");
    }
     
    // 호이스팅 결과. 위와 동일
     
    var foo2; // 호이스팅. 함수표현식의 변수값 선언
     
    //호이스팅. 함수선언문
    function foo() {
        console.log("안녕");
    }
     
    foo(); // 안녕
    foo2();   // error
     
    foo2 = function () {
        console.log("하이루");
    }
    cs

    호이스팅은 함수선언문과 함수표현식에서 서로 다르게 동작하기 때문에 주의해야합니다

    변수에 할당된 함수표현식은 끌어 올려지지 않기 때문에 이때는 변수의 스코프 규칙을 그대로 따릅니다

    foo2()가 에러인 이유는 함수표현식은 함수선언문과 달리 선언과 호출 순서에

    따라서 정상적으로 함수가 실행되지 않을 수 있습니다

    그래서 함수표현식의 선언이 호출보다 위에 있어야 합니다

    (역시 스코프 포스팅은 따로 해야겠다. 그리고 예제에서 호이스팅 되기 전처럼 코드를 짜는 사람이 있을까...?)

     

    💥 호이스팅 결론...

    1. 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 함수와 변수는 가급적 코드 상단부에 선언합니다
    2. var보다는 let/const를 사용합니다

    (개인적으로 자바스크립트 시작을 var는 되도록 쓰지말고(그냥 웬만해선 무조건 쓰지 말라) let과 const를 쓰라고 배웠기 때문에

    var가 쓰여진 옛 문서들을 보면 너무 혼란스럽습니다ㅠㅠㅠ 아직도 많은 문서들에서 var가 쓰이고 있죠...)

    반응형

    댓글