호이스팅에 대해

지난 달 우연히 회사에서 개발자 채용 면접을 부사수 면접관으로 참여하였다.

호이스팅에 관한 질문이 나왔는데, 나는 속으로 “var, 함수 선언문 이 두개만 설명하면 되겠네” 예상 했는데

사수님이 원하신 답변은 그게 아닌걸 보고 옆에서 약간 찔렸다.. 😨

호이스팅에 관해 깊게 분석하고자 포스팅을 남긴다.


“끌어 올린다” 표현은 오히려 더 헷갈리게 만든다.

호이스팅

호이스팅이라는 단어의 근본적 시초는 부둣가 선박장에 가보면 무거운 컨테이너를 끌어 올려서 배에 올려두는 작업 절차를 호이스팅이라고 부른다.

value = 123

var value

console.log("test :", value) // test : 123 

위 코드를 보면 변수를 선언하기도 전에 할당을 하고 난 후 진행하는데 콘솔 로그에선 123 이라는 값이 로그에 찍힌다.

여기서 끌어 올린다는 표현을 코드로 도출하면 아래와 같이 해석할 수 있다.

var value

value = 123

console.log("test :", value) // test : 123 

그러나 자바스크립트 동작 과정에 대해 알고 있으면 저런 코드 형태를 직관적으로 해석 하기엔 모순이 있다.

자바스크릡트 V8 엔진은 특성상 코드를 실행 하기 전 작성된 코드들을 한번 검토 하는 과정이 있다.

  1. 작성된 코드들이(함수, 변수) 나열되어 있다. => call stack 동작 과정
  2. 각 작성된 코드에 관해 체크를 하며 모두 메모리에 담아 놓는다. => meomory heap 동작 과정

2번 과정의 변수가 선언하기 전에 할당된 변수가 발견 될 경우 놓친 부분을 수정하여 최상단에 선언하였다고 인식하고 메모리에 저장을 한다. 다시 말해, “끌어 올린다는” 표현보단 코드가 실행 되기 전에 사전 검토 후 각 변수와 함수들의 메모리 주소를 등록한다 라는 메커니즘을 파악하는 것이 더 중요하다. 아마 자바스크립트 개발자들이 위 과정을 쉽게 이해 시키기 위해 호이스팅(끌어 올린다)라는 뜻으로 쉽게 설명을 했을 것이다.

위 과정이 이해가 안갈 수도 있는데 아이돌 그룹들이 무대 촬영 전 과정을 비유하면 이해가 확 올 수도 있다.

  1. 2023-07-10(월): 2023.07.15(토) 20시 40분 KBS 뮤직뱅크 라이브 무대 진행 스케줄 확정 => 코드 작성
  2. 2023-07-15(토) 16시 30분: 본 무대 전 리허설 및 스탭 장비 사전 체크 => 작성된 코드 체크 후 메모리 저장
  3. 2023-07-15(토) 20시 40분: 라이브 무대 시작 => 코드 실행

그냥 리허설 한번 진행 후 무대에 나서듯 자바스크립트 코드들도 “리허설 과정을 한번 테스트 후 코드를 실행한다” 라고 생각하면 된다.


let, const 변수 키워드는 호이스팅이 발동되지 않을까?

var의 고질적인 문제는 참 많다. 예를 들어 재선언 및 재할당이 무분별하게 가능하고 이러한 문제들은

코드가 방대해지면 가독성에 혼란을 주게 되는데 ES6 부터 이 문제를 해결하고자 let , const 변수 키워드가 등장하였다.

console.log(value)
const value = 5
console.log(value)

위 코드의 실행 결과는 참조 에러(ReferenceError)가 발생 된다.

let과 const는 호이스팅이 안되기 때문에 에러가 발생하였다고 오해할 수 있는데, 사실 let과 const도 호이스팅은 발동된다.

그러나 Temporal Dead Zone(TDZ) 이라는 사각지대 공간에 있기 때문에 접근을 못하게 되어 에러가 발생하게 되는 것이다.

TDZ는 스코프의 시작 지점부터 초기화 시작 지점까지의 구간 을 의미하며 let과 const는 TDZ 구간에 의해 메모리가 할당이 되질 않아 참조 에러(ReferenceError) 발생하게 된다.

이렇게 정리하다보면 호이스팅의 “끌어올린다” 라는 뜻은 동작 원리에 대해 깊게 이해하는데 더 혼란을 줄 수 있다.


스코프 범위에 대한 호이스팅

// step 1
for(var value = 1; value < 5; value++){ 
}
console.log(value) // 5

// step 2
function add() {
    var value = 0
    return value + 9
}
console.log(value) // ReferenceError!!

위 코드에서 각각 지역 스코프를 보유하고 있는데 차이는 무엇이 있을까?

step 1 => for 문 지역 스코프 안의 변수 value는 외부에서 접근이 가능 하다. step 2 => 함수 지역 스코프 안의 변수 value는 외부에서 접근이 불가능 하다.

잘 겪지 못하면 헷갈릴 수도 있는데 if, for 문 등등 이 경우의 지역 스코프에 선언된 변수들은 외부에서도 접근이 가능하다. 즉, 호이스팅으로 인해 코드 실행 전 메모리 주소들이 등록되었다는 것을 알 수 있다.

반대로 함수의 지역 스코프 만이 호이스팅 과정에서 메모리 주소가 등록되지 않으므로 참조 에러가 발생할 수 있어 지역 스코프에 관한 호이스팅 차이를 명확히 알고 있어야 한다.