본문 바로가기
웹 엔지니어 면접 질문/HTML, CSS and Javascript

Hoisting이란? 핵심만 알고가자

by cuziam 2023. 4. 28.

호이스팅이 무엇이고, 언제 발생하는지 예시코드를 통해 알아본다. 그리고 호이스팅이 문제가 되는 지점에 대해서도 알아본다. 인터넷에서 프론트엔드 면접 자료를 찾아보면, 호이스팅에 관한 것은 단골 질문으로 자주 출제된다고 한다.
 
*실행 컨텍스트, 렉시컬 환경, 스코프, var let const의 차이점에 대한 질문도 연계되어 나올 가능성이 높다. 하지만 이 글은 그 부분까진 다루지 않고 호이스팅의 핵심부분만 다루려고 한다. 해당 주제들은 따로 글을 만들어서 다루려고 한다.
 

Question 1: 호이스팅이 무엇인가요?

Hoist의 원래 의미는 ‘(밧줄 혹은 장비 등으로) 끌어올리다.’라는 뜻이다. 원래의 의미와 유사하게, 자바스크립트에서 호이스팅(hoisting)은 변수나 함수의 선언이 코드의 최상단으로 끌어올려진 것처럼 동작하는 것이다. 좀 더 정확히 말하면 자신이 속한 스코프의 최상단으로 선언들이 끌어올려진 것 처럼 동작하는 것을 의미한다.
*실제로 선언들이 코드의 상단으로 끌어올려지는 것은 아니다.
 

Question 2: 호이스팅은 왜 발생하나요?

결론부터 말하자면, 자바스크립트에서 선언한 변수(var), 함수는 런타임 이전에 기본값이 할당되기 때문이다. 짧게 말하면, 미리 선언과 할당이 이루어지는 것이다. 변수는 ‘undefined’, 함수의 경우 ‘함수 객체’가 할당된다.

 

Qustion 3: 호이스팅은 언제 발생하나요?

변수 호이스팅 예시와 함수 호이스팅 예시를 들어보겠다.

  • 변수 호이스팅 예시
console.log(name); // undefined
var name = "John";

원칙적으로 name이 선언되기 전에 console.log가 name을 호출했으므로, 에러가 발생해야하는 것이 맞다. 하지만 호이스팅으로 인해 name은 이미 선언되어 undefined값을 부여받은 상태이므로, 오류가 발생하지 않는다.

  • 함수 호이스팅 예시1- 함수 선언 호이스팅
console.log(greet()); // Hello, world!

function greet() {
  return "Hello, world!";
}

거의 유사하게 greet()함수 역시 선언되기 전에 호출되었으므로, 에러가 발생해야하지만, 호이스팅으로 인해 greet()함수는 미리 선언되고 함수 객체로 초기화된다. 따라서 호출 시 오류가 발생되지 않는다.

  • 함수 호이스팅 예시2-함수 표현식 호이스팅
console.log(sayHello); // undefined
console.log(sayHello()); // TypeError: sayHello is not a function

var sayHello = function() {
  return "Hello, world!";
};

함수 표현식으로 만든 함수는 변수로 취급된다. 따라서 함수 표현식으로 만들어진 함수는 ‘변수 호이스팅’이 적용된다. 따라서 런타임 이전에 sayHello 값은 함수 객체가 아닌 undefined로 초기화된다. 따라서 sayhello()를 미리 실행하면 typeerror가 발생한다.
 

Question 4: 코드 작성 시 호이스팅을 고려해야 하는 이유가 무엇인가요?

프로그래밍 시 기본 원칙 중 하나가 ‘코드 상에서 변수나 함수가 호출되기 전에 선언되어야 한다’는 점인데 이를 위반하기 때문이다. 이 때문에 예상치 못한 버그가 발생하기에 유의해야 한다.
*이러한 이유 때문에 JSON을 발명한 더글라스 크록포드라는 분은 함수를 만들 때 함수 표현식을 권장하기도 했었다.
 

Question 5: Let과 Const의 경우엔 호이스팅이 어떻게 발생하나요?

let과 const은 호이스팅 되지만, var과 다르게 값이 아예 할당되지 않는다. 그리고 값이 실제로 할당되어 초기화되기 전까지 빈 값이 들어가 있는 것이다. (메모리의 관점에서 보면 쓰레기 값이 들어가있는 셈이다.) 이 때 호이스팅이 발생한 후, 변수가 실제로 초기화되기 전까지의 구간을 TDZ(Temporal Dead Zone, 일시적 사각지대)라고 부른다. 이 TDZ를 이용하여, 혹시나 발생할 수 있는 쓰레기값 접근 오류를 막는다.

// 여기서 변수 'name'은 TDZ에 있음

console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "John"; // 변수 초기화

// 여기서 변수 'name'은 정상적으로 사용 가능
console.log(name); // "John"

만약에 TDZ에 놓은 let과 const 변수에 접근하려고 하면 ReferenceError: Cannot access before initialization(참조 오류: 초기화 이전에 접근할 수 없음) 에러를 얻게 된다.
 
<참고했던 글>

 

Hoisting in JavaScript with let and const – and How it Differs from var

I used to think that hoisting only happened to variables declared with var. But recently, I learned that it also happens to variables declared with let and const. I'll explain what I mean in this article. I also have a video version of this article [https:

www.freecodecamp.org

 

What's the difference between variable definition and declaration in JavaScript?

Is this a variable definition or declaration? And why? var x; ..and is the memory reserved for x after this statement? EDIT: In C extern int x; is a declaration, int x = 5; is a definition. What...

stackoverflow.com