호이스팅이 무엇이고, 언제 발생하는지 예시코드를 통해 알아본다. 그리고 호이스팅이 문제가 되는 지점에 대해서도 알아본다. 인터넷에서 프론트엔드 면접 자료를 찾아보면, 호이스팅에 관한 것은 단골 질문으로 자주 출제된다고 한다.
*실행 컨텍스트, 렉시컬 환경, 스코프, 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(참조 오류: 초기화 이전에 접근할 수 없음) 에러를 얻게 된다.
<참고했던 글>
- 모던 자바스크립트 deep dive, 이웅모 지음
- https://www.freecodecamp.org/news/javascript-let-and-const-hoisting/-> 이 글은 var, let 그리고 const가 어떤 식으로 호이스팅되는 지에 대해 다룬다.
- https://stackoverflow.com/questions/20822022/whats-the-difference-between-variable-definition-and-declaration-in-javascript/52772789#52772789-> 이 글은 C/C++에서 말하는 '선언'과 '정의'의 의미를, javascript에서 어떤 개념으로 치환할 수 있는지에 대한 질문과 그에 대한 답이다.
'웹 엔지니어 면접 질문 > HTML, CSS and Javascript' 카테고리의 다른 글
함수 선언문과 함수 표현식의 차이 (0) | 2023.05.01 |
---|---|
var, let, const의 차이점 간결하게 요약! (0) | 2023.05.01 |