[JavaScript] 호이스팅(Hoisting)

조은·2022년 9월 14일
0

호이스팅이란?

스크립트를 로드할 때 전체 코드를 확인한 후 선언된 함수와 변수(var) 가 인접 스코프의 최상단에서 관측가능한 현상을 의미한다.

호이스팅에 대한 오해

많은 곳에서 함수와 var로 선언한 변수에만 일어난다고 설명했지만,
위에서 정의한 호이스팅의 경우에는
let과 const에도 동일하게 작용한다.

하지만!

  • var로 선언한 변수는 호이스팅시 undefined로 변수를 초기화한다.
  • 반면 let과 const로 선언한 변수는 호이스팅시 변수를 초기화하지 않는다.

그래서 선언 이전에 사용하려고 했을 때 var로 선언한 변수는 undefined가 출력되고 let,const로 선언한 변수는 에러가 뜨는 것이다.

예시

print();	

function print(){
	console.log("Hello, world"";
}

print()가 정의되기 전에 호출했지만,
스크립트가 로드될 때 print()는 코드의 최상단으로 hoist되어서 초기화까지(undefined로) 된다.
따라서 문제 없이 실행된다.


JS는 코드를 실행하기 전에 따로 컴파일 과정을 거친다.
(컴파일이라는 건 사람이 이해하는(고수준) 언어로 이루어진 코드를 컴퓨터가 이해할 수 있도록(저수준) 쪼개고, 체계적인 구조로 재가공하여 전체를 분석하는 일련의 과정이다.)

이 과정에서 JS 엔진은

  • 모든 스코프(or 실행 컨텍스트)를 탐색하며 각 스코프의 변수 객체에 여러 식별자를 수집한다.

  • 실행 시점으로 넘어가기 전에 선언된 식별자에 대한 정보를 이미 알고 있기 때문
    -> 스코프의 어느 지점이든 관련된 함수/변수를 참조할 수 있는 것이다.

그렇지만 함수/변수에 상관없이 늘 동일한 규칙이 적용되지는 않는다.
즉, 호이스팅에도 규칙이 존재한다.



호이스팅 규칙

호이스팅은 크게 함수 호이스팅변수 호이스팅으로 나뉜다.
그리고 해당 개념에 관한 규칙을 요약하면 다음과 같은 항목으로 이루어진다.

  1. 선언된 함수는 상단에서 참조, 호출이 가능하다.
  2. 선언된 var 는 상단에서 참조, 할당이 가능하다.
  3. 선언된 let , const 는 상단에서 참조, 할당이 불가능하다.

함수 호이스팅(Function Hoisting)

함수 호이스팅은 다른 무엇보다 가장 먼저 이루어진다.
그리고 함수 호이스팅은 선언문에만 해당한다.
함수를 선언하는 것도 결국에는 변수에 함수를 할당하는 것과 같다고 이해하면 된다.

var value = 'value';
var func = function () {};

함수의 선언문은 식별자가 변수 객체에 수집될 때( = 호이스팅돼서 끌어 올려질 때)
부가적으로 해당 함수 참조에 대한 초기화까지 자동으로 이루어진다.
그래서 선언된 함수는 상단에서 참조, 호출이 가능하다.

변수 호이스팅(Variable Hoisting)

변수는 프로그램 내에서 크게 세 가지 단계를 거친다.

  1. 선언 : 파싱 과정에서 변수 객체가 변수에 대한 식별자들을 수집한다.
  2. 초기화 : 식별자에 메모리를 할당하고 undefined 상태를 부여한다.(초기화)
  3. 할당 : 변수 안에 직접 값을 넘겨 준다.

함수 호이스팅 과정에서처럼 변수 또한 마찬가지로 선언과 초기화를 해주어야만 값의 참조 및 할당이 가능하다.
다만 변수를 어떻게 선언했는지에 따라 선언, 초기화 시점이 달라질 수 있다는 점을 유의해야 한다.

  • var 는 호이스팅이 발생하면, 선언과 초기화가 거의 동시에 이루어진다. 실행 시점의 스코프 최상단에서 해당 변수에 대한 메모리가 살아있기 때문에 선언부 위치에 상관 없이 참조, 할당이 가능하다.
  • let , const 는 호이스팅이 발생하면, 선언만 이루어지고 실행 시점에서 실질적인 선언부를 만날 때까지 초기화는 이루어지지 않는다. 이 간극만큼 해당 변수에 대한 메모리는 존재하지 않기 때문에 선언부 상단에서 참조, 할당이 불가능하다.

let, const 가 동작하는 과정에서 스코프의 진입지점과 해당 식별자의 실질적 선언부 사이를 일시적 사각지대, TDZ(Temporal Dead Zone) 라고 한다. 여기서 변수는 존재하지만, 초기화가 되어있지 않다.

{
  /*
   * Temporal Dead Zone of a
   * a는 이 구간에서 참조할 수 없다.
   * console.log(a) // Reference Error
   */
  let a;
}
  • 호이스팅은 선언만 포함한다는 쪽이 있는 반면, 선언 - 초기화까지 포함해야 한다는 쪽도 있다.

  • 그래서 let, const는 호이스팅의 범주에 들어갈 수 없다는 것이 그들이 주장하는 바이다.




아래의 코드에서 console.log 를 호출하기도 전에 에러를 반환하는 이유는 결국 해당 문의 실행 전에 let 의 식별자를 관측했기 때문이다.

따라서, let,const도 호이스팅의 범주에 들어갈 수 있다고 볼 수도 있다

function a() {}

console.log(a);

let a;
// SyntaxError: Identifier 'a' has already been declared

‘호이스팅은 인접 스코프의 상단에서 선언부를 관측할 수 있는 현상’이라는 처음의 설명에 빗대어 보면 let 과 const 또한 호이스팅 대상이라고 보는 게 맞다.



How To Use?

함수 호이스팅

함수 호이스팅은 추상화 수준으로 나뉜 여러 함수를 어떤 식으로 나열할지 고민해보면 사용법에 대한 답을 내릴 수 있을 것 같다. 위에서부터 읽어 내려나가는 게 편할 수도 있고, 표현식의 일관성을 더 맞추어주고 싶을 수도 있다. 이는 팀으로 운영되는 프로젝트라면 컨벤션적인 부분으로 해결할 수 있겠다.

function handler() {
  util();
}

function util() {}

/ 이렇게 쓸 수도 있다. /

var util = function () {};

var handler = function () {
  util();
};



변수 호이스팅

변수 호이스팅은 엄격히 지양되고 있다.

값을 덮어 씌워 얻을 수 있는 이점도 없거니와 코드의 오류 발생 소지를 다분히 높일 수 있기 때문이다.
let 과 const 가 출현하게 된 이유를 생각해보자
TDZ 이슈 때문에 사용하는 것이 망설여진다면 애초에 처음부터 스코프의 상단에 변수를 선언해줌으로 해당 이슈를 방지하면 된다.

{
  const a = 1;
  let b = 2;
  //logic...
}




출처 : https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/
(Tecoble - 호이스팅에 대한 오해와 진실)

profile
끄적끄적....

0개의 댓글