Javascript 코어 개념 - 호이스팅

Ina·2020년 9월 20일
2

TIL

목록 보기
8/20
post-thumbnail
post-custom-banner

📍 호이스팅이란?

: JS 엔진이 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 대체한 가상의 개념.

🔸 environmentRecord와 호이스팅

environmentRecord는 실행 컨텍스트에서 실행하는 정보 중, VariableEnvironment & LexicalEnvironment 를 구성하는 정보 중 하나. 현재 컨텍스트와 관련된 코드의 식별자 정보 등이 저장된다.

→ 식별자 : 컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수 자체, var로 선언된 변수의 식별자 등.

"JS엔진은 실행 컨텍스트가 관여할 코드들을 실행하기 이전에 변수 정보 수집을 끝마치고 있는 레디 상태임" ⇒ 이 개념을 식별자들을 최상단으로 끌어올려(hoist)놓은 다음 실제 코드를 실행한다는 개념으로 이해하기 쉽게 해석한 것이 바로 Hoisting


🔸 호이스팅의 예시

1. 매개 변수&변수의 호이스팅

BEFORE 호이스팅

    function hello(x) { //수집대상 1(매개변수)
        console.log(x);
        var x; //수집대상 2(선언된 변수)
        console.log(x);
        var x = 2; //수집대상 3(선언된 변수)
        console.log(x);
    }

    hello(1);

AFTER 호이스팅

    function hello( ) { 
        var x; //수집대상 1(매개변수)
        var x; //수집대상 2(선언된 변수)
        var x  //수집대상 3(선언된 변수)
        x = 1; //함수 호출시 매개변수에 할당된 값
        console.log(x);
        console.log(x);
        x = 2;
        console.log(x);
    }

    hello(1);

2. 함수선언 호이스팅

BEFORE 호이스팅

    function a () {
        console.log(b); // (1)
        var b = 'bbb'; //수집대상 1(선언된 **변수**)
        console.log(b); //(2)
        function b () {} //수집대상 2(선언된 **함수**)
        console.log(b); //(3)
        };
    a();

AFTER 호이스팅

    function a () {
        var b; //수집대상 1(선언된 **변수**) ====> 변수는 선언부만 끌어올려짐(hoisted)
        function b () {} //수집대상 2(선언된 **함수**)	===> 함수는 전체가 끌려올라감
        console.log(b); // (1)
        b = 'bbb';
        console.log(b); //(2)
        console.log(b); //(3)
        };
    a();

⚠️ 변수는 선언부만 hoisting되고, 함수는 함수 전체가 hoisting되는 이유?
: JS창시자인 브랜든 아이크가 JS를 유연하고 쉬운 언어로 만들고자 했기 때문. 덕분에 함수를 선언한 위치와 무관하게 실행할 수 있게 됐지만 많은 혼란도 함께 야기됨.


📍 같이 알면 좋은 내용

🔸 함수 선언문과 함수 표현식

함수를 정의하는 3가지 방식

(1)함수 선언문 (2) 익명 함수 표현식 (3) 기명 함수 표현식

//(1) 함수 선언문
function a () { //do something } //**함수명 a = 변수명**.

//(2)익명 함수 표현식
var b = function () { //do something } //**변수명 b = 함수명**.

//(3)기명 함수 표현식
var c = function d() { //do something } //**변수명 c, 함수명 d (같지 않음)**

❖ 과거에는 디버깅 용이하게 할 목적으로 기명함수를 사용했었으나 이제는 브라우저들이 똑똑해져서 굳이 필요하지 않다고 함.(+기명 함수 표현식의 함수명(d)으로는 함수 내부에서만 호출 가능하고 외부에서는 호출 안 됨😕 )

🔸 함수 선언문 & 함수 표현식의 호이스팅

BEFORE 호이스팅

    console.log(sum(1,2));
    console.log(multiply(3,4));

    function sum(a,b) {  // 함수 선언문 - 함수명 sum(=변수명)
        return a + b; 
    }

    var multiply = function (a,b) {  //함수 표현식 - 변수명 multiply(=함수명)
        return a * b; 
    }

AFTER 호이스팅 후

    function sum(a,b) {  // 함수 선언문
        return a + b; 
    }
    var multiply;  //함수 표현식 - 변수명

    console.log(sum(1,2));
    console.log(multiply(3,4));

    multiply = function (a,b) {  //변수 할당부인 실제 함수 부분은 제자리에 남음.
        return a * b; 
    }

⚠️ 함수 선언문의 위험성 예시

😎 선임이 a 함수를 1번째 줄에서 함수선언문 으로 선언해놓음

🤓 (호이스팅 개념 없는)신입이 10,000번째 줄에서 함수선언문 으로 a 함수의 내용을 수정해버림.

→ 신입은 1~9999번째 줄까지는 수정한 함수가 영향을 끼치지 않을 거라고 생각했지만, 함수선언문의 함수 전체가 호이스팅 되고 선임이 짠 코드가 다 어그러져버림!

⇒ 만약 선임과 신임 둘다 함수 표현식으로 함수를 정의했다면 문제가 없었을 것!


🔸 let과 const는 호이스팅이 되지 않는다?(ㄴㄴ오해입니다!)

let이 호이스팅되지 않는 "것처럼" 보이는 예시

    console.log(name); 
//ReferenceError: name is not defined
    let name = 'seo';

→ name 선언 이전에 호출시 reference error가 나서 let은 호이스팅이 되지 않는다고 생각할 수 있음.

🔺 but, 호이스팅 되지 않아서가 아니라 let의 변수 생성과정이 var와 다르기 때문임

- var, let, const의 변수 생성과정 비교

  • (기본적으로 변수는 선언-초기화-할당의 3단계 생성과정을 가짐)
  • var : 선언&초기화 동시에 이뤄짐. (선언부 & 초기화 세트로 다님)
  • let : 선언 - 초기화 분리되어 진행 (선언부만 단독으로 호이스팅됨)
  • const : 선언&초기화 동시에 해야 함. (선언부 & 초기화 세트로 정의해줘야 하지만 세트로 호이스팅 되진 않음)

let으로 선언한 name은 맨 위로 선언부가 호이스팅이 되긴 됐으나, 초기화(메모리 할당)가 아직 되지 않았기 때문에 reference error가 나게 되는 것.

+)

let & const 로 선언된 변수는 블록 레벨 스코프를 가짐. 즉, {} 내부에 변수를 선언하면 해당 블록 내부에만 생명주기가 유지됨. 반대로 var는 함수 레벨 스코프를 가지므로, 블록 내부에 선언되어도 외부에서 접근할 수 있음.


Reference

profile
프론트엔드 개발자. 기록하기, 요가, 등산
post-custom-banner

0개의 댓글