호이스팅에 대해 설명해보시오

ChangHyeon Bae·2022년 11월 24일
0

JavaScript

목록 보기
2/8
post-thumbnail

처음 호이스팅이라는 말에 대해 알게 되었을 때 단순히 함수와 변수를 최상단에 끌어올리는 정도로의 개념만을 이해하고 넘어갔었다. 이후에 면접에 대비해 내가 알고 있는 개념에 대해 얼마나 논리적으로 설명이 가능할까를 생각 해보게 되었고, 블로그 글을 써보면서 기록을 남기며 개념을 정리해보기로 했다!


🙋‍ 호이스팅이란?

앞서 말했 듯이 단순히 함수와 변수를 최상단에 끌어올린다는 단순한 개념으로만 알고 있었다. 먼저 호이스팅의 정의부터 천천히 알아가보자.

MDN 웹문서에서는 호이스팅을 밑에와 같이 간단하게 소개하고 있다.

인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미

인터프리터는 또 뭘까?
프로그래밍 언어의 소스코드를 바로 실행하는 컴퓨터 프로그램 또는 환경
이라고 나무위키에 적혀있다. (기회가 된다면 나중에 자세히 톺아보자)

하지만 이러한 사전적 의미만 읽어서 정확히 호이스팅이란 무엇인가에 대해 알기가 어렵다. 그래서 호이스팅에 대해 알아보며 몇가지 오해와 이것을 가능하게 하는 매커니즘에 대해 알아 보았다.

우선 먼저 알아야 될 선지식으로는 JS코드는 실행하기 전에 따로 컴파일 과정을 거친다는 사실을 인지할 필요가 있다.

❗️여기서 잠시, 컴파일이란?

사람이 이해하는(고수준) 언어로 이루어진 코드를 컴퓨터가 이해할 수 있도록(저수준) 쪼개고, 체계적인 구조로 재가공하여 전체를 분석하는 일련의 과정

위 과정을 통해 JS엔진은 모든 스코프 or 실행컨텍스트를 탐색하며 각 스코프의 변수 객체에 여러 식별자를 수집한다. 즉 실행 시점으로 넘어가기 전에 선언된 식별자에 대한 정보를 이미 알고 있기 때문에 스코프의 어느 지점이든 관련된 함수/ 변수를 참조할 수 있는 것이다.

실행컨텍스트가 무엇인지에 대해 가볍게 알고 가자 😃

  • 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
  • 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념

실행 컨텍스트에 대한 개념은 이정도로 가볍게만 알아두고 앞서 말한 호이스팅에 대해 자세히 이해하기 앞서 변수가 어떻게 생성되며, 다음으로 호이스팅이 어떻게 이뤄지는지에 대해 3가지 단계를 먼저 나누어서 생각해 보자!

📖 생성단계 보기


1단계 : 선언 단계(Declaration Phase)

  • 변수를 실행 컨텍스트의 변수 객체에 등록한다.
  • 이 변수 객체는 스코프가 참조하는 대상이 된다.

2단계 : 초기화 단계(Initializetion Phase)

  • 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
  • 이 단계에서 변수는 undefined로 초기화 한다.

3단계 : 할당 관계(Assignment Phase)

  • undefined로 초기화된 변수에 실제 값을 할당한다.

변수가 할당되는 3단계를 통해 어느정도 감이 잡히는 듯하다.
하지만 우리가 아는 변수 선언법에는 var, let, const 이렇게 3가지가 있는데 모두 다 undefined로 초기화되고, 호이스팅이 이루어지는 것일까?
결과부터 말하자면 반은 맞고, 반은 틀리다고 말할 수 있다.

📝 변수 선언 호이스팅

  1. 먼저 var는 호이스팅이 발생하면, 선언과 초기화가 거의 동시에 이루어진다.
    실행 시점의 유효 스코프내 최상단에서 해당 변수에 대한 메모리가 살아 있기 때문에 선언부 위치에 상관없이 참조, 할당이 가능하다.

예시를 통해 위에 했던 말을 이해해보자

console.log(text); // Eddie 출력
text = "Eddie" // 선언된 변수에 값을 할당 
var text; 
// 선언과 초기화가 거의 동시에 이루어지고 초기화하는 값으로 undefined가 들어간다.

밑에 코드부터 위로 읽어보자. 우리가 생각하는 정상적인 코드는 위에서 아래로 순차적으로 읽어진다고 생각하지만 위 예시를 통해 호이스팅은 코드의 순서에 제약을 받지 않고 선언부를 최상단으로 끌어올린다는 것을 다시 한번 알 수 있다.

  1. let, const 도 호이스팅이 발생하면 undefined로 초기화가 이루어질까? 정답부터 말하면 letconst는 선언은 이루어지지만 초기화는 이루어지지 않는다.

밑에 예시코드를 보며 이해해 보도록 하자.

function a() {}

console.log(a);

let a;
//Uncaught SyntaxError: ReferenceError: a is not defined

위 예시와 같이 해당 스코프의 상단에서 let으로 선언된 변수가 관측되는것을 알 수 있다. 위 결과를 통해 호이스팅은 된다는 것을 알 수 있다.

일각에서는 호이스팅은 선언만 포함한다( var, let, const )는 쪽이 있는 반면,
선언 - 초기화( var )만 호이스팅의 범주에 들어가야한다는 의견이 있다.
나의 경우에는 전자가 맞다고 생각한다. 그에 대한 이유로는

MDN 문서를 참고

  1. let, const로 선언한 변수의 경우 호이스팅시 변수를 초기화하지 않는다는 안내
  2. 변수의 초기화를 수행하기 전에 읽는 코드가 먼저 나타나는 예외발생을 통해 관측은 되나 에러를 발생시킨다는 것을 다시 한번 확인 할 수 있다.
    결과적으로, let const 도 호이스팅이 이루어지나 에러를 발생 시킨다는 것통해 호이스팅이라는 개념의 범주 안에 있다는 것을 알 수 있습니다.

( 공식문서를 생활화하자 )

📝 함수 선언 호이스팅

다시 한번 호이스팅의 정의에 대해 다시 한번 말해보자.

변수뿐만 아니라 함수도 호이스팅이 이루어지는데 함수는 어떻게 이루어 질까?
함수를 표현하는데에는 선언문과 표현식이 있다. 그럼 이 두개의 방법 모두 호이스팅이 제대로 이루어질까? 밑에 예시코드를 통해 알아보자

foo1(); // 함수 선언문에서는 호이스팅 일어난다.
foo2(); // 함수 표현식은 호이스팅이 일어나지 않는다.

function foo1() {
  console.log('foo1');
}

var foo2 = function() {
  console.log('foo2);
}
// Uncaught TypeError: foo2 is not a function          

밑에 예시 코드를 보면서 표현식을 썼을 때 나온 TypeError에 대해 알아보자!
var foo; // undefined

foo(); // 변수인데 왜 함수 호출해?

var foo = function () { // 변수 foo에 함수를 넣는다.
  console.log('foo');   
}

var는 호이스팅의 으로 인해 해당 스코프의 최상단으로 끌어올려진다.
그러므로 var foo가 가장 먼저 실행이 된다. 변수에 아무 값도 담기지 않으므로 초기화 상태인 undefined 상태이다.
그 후로 foo()가 호출되면 위에 선언한 foo가 호출 되므로 변수를 호출하게 된다. 그러므로 foo() 는 변수인데 왜 함수야?라는 TypeError 가 발생한다.

아래 예시코드는 let, const로 변수를 선언했을 때 나오는 결과이다.

foo();

let foo = function() {
  console.log('foo'); 
} //Uncaught ReferenceError: foo is not defined

여기서 나오는 에러는 const로 선언했을 때와 같은 에러이며, var로 선언했을 때와는 다른 에러가 나온다.

그 이유는 var는 선언했을 때와 거의 동시에 undefined로 초기화가 이루어지지만 let, const는 선언만 이루어지기 때문에, 선언만 이루어진 변수를 호출하면 참조 오류가 발생한다.

함수 선언문만 호이스팅이 된다고해서 이 방법만 사용하고 안하고 하는것이 아니다.
위에서부터 읽어 내려나가는게 편할 수도 있고, 또 어떤 사람은 표현식을 권장하는 경우도 심심치 않게 있다. 이는 팀으로 운영되는 프로젝트라면 컨벤션적인 부분을 정하고 많이 따르는 편이다.

하지만❗️

변수 호이스팅은 엄격히 지양되고 있다.
값을 덮어 씌워 얻을 수 있는 이점도 없고, 코드의 오류 발생 소지를 높일 수 있기 때문이다. var의 유연한 특성 때문에 발생할 수 있는 여러 피해를 방지하고자 letconst가 출현한 것인데 TDZ이슈 때문에 사용하는 것이 망설여진다면 애초에 속해있는 해당 스코프 최상단에 변수를 선언해줌으로써 이슈를 방지하면 된다.

TDZ(Temporal Dead Zone)란?

일시적인 사각지대, 스코프 시작 ~ 초기화 시작 사이의 구간을 의미
변수가 선언되고 변수의 초기화가 이루어지기전까지의 구간
TDZ 에서는 선언 되기 전이거나 초기화 되기 전인 상태의 변수를 사용하는것을 허용하지 않는다.

🧐 정리

코드의 가독성과 유지보수 그리고 발생할 가능성이 있는 오류를 방지하기 위해 호이스팅이 일어나지 않도록 한다. 그래서 개인적으로 코드 작성 시 호이스팅의 영향을 최소화 하기 위해 var를 배제하고 const, let을 사용하고 있다.

호이스팅에 대해 다시 공부하면서 알게 된 것이 있다. 호이스팅은 엔진의 특별한 능력도 아니고 실행시점에서 발생하는 현상이 아니다. 단지 JS의 특성에 따라 코드 실행전 컴파일을 거치며 자연스럽게 귀결되는 전처리 과정이라는 것을 알게 되었다.

🔗 참고

https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/
https://hanamon.kr/javascript-%ed%98%b8%ec%9d%b4%ec%8a%a4%ed%8c%85%ec%9d%b4%eb%9e%80-hoisting/
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%8A%A4%EC%BD%94%ED%94%84-%ED%95%A8%EC%88%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85#%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85(Hoisting)
https://noogoonaa.tistory.com/78

정확하지 않은 정보가 있을 수 있습니다. 댓글을 통해 피드백 주시면 적극적으로 반영하겠습니다🥲

profile
모든 결과는 내가 하기 나름이다 🔥

0개의 댓글