호이스팅이란?

자바스크립트 엔진실행 컨텍스트를 구성할 때 environmentRecord 에 식별자의 정보를 수집한다. 이러한 과정을 통해 엔진은 함수를 실행하기도 전에 해당 컨텍스트 내부의 변수명들을 이미 알고 있다.
이렇기에 식별자들을 코드의 최상단으로 끌어올렸다! 라는 호이스팅이라는 개념이 생겨났다. 물리적으로 끌어올린 것이 아닌, 실행 컨텍스트 관점에선 이미 식별자들의 정보를 알고 있으니 식별자 정보를 수집하는 과정을 이해하기 쉬운 방법으로 나타낸 추상화한 가상 개념이다.

  • 호이스팅은 코드를 실행하기 전 변수/함수선언을 해당 스코프의 최상단으로 끌어올리는 것이 아니다.
  • 호이스팅은 코드가 실행하기 전 변수/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상이다.
  • 자바스크립트 엔진은 코드를 실행하기 전 실행 가능한 코드를 형상화하고 구분하는 과정(실행 컨텍스트)를 거친다.
  • 자바스크립트 엔진은 코드를 실행하기 전 실행 컨텍스트를 위한 과정에서 모든 선언(var,let,const,function,class)을 스코프에 등록한다.
  • 코드 실행 전 이미 변수/함수선언이 저장되어 있기 때문에 선언문보다 참조/호출이 먼저 나와도 오류 없이 동작한다.

스코프란(Scope)?
JavaScript에서 Scope(스코프)변수에 접근할 수 있는 범위를 말한다.
식별자(변수)를 찾기위한 규칙이라고도 한다.



변수 호이스팅(var,let,const 키워드)

  • 자바스크립트의 모든 선언에는 호이스팅이 일어난다.
  • 하지만 let,const,class를 이용한 선언문호이스팅이 발생하지 않는 것처럼 동작함.
  • var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생한다.
  • 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.

여기서 중요한 점은 호이스팅이라는 용어가 '선언이 먼저 메모리에 저장되었다.'는 것을 의미하기 때문에 즉, '선언이 끌어올려진다'는 의미이기에 모든 선언은 호이스팅이 일어난다는 말은 참이다.

즉, 호이스팅이 파일의 맨 위로 끌어올려진 것 같은 현상을 의미하기에 선언문 이전에 참조해서 에러를 발생(let 키워드 사용시)시킨다고 호이스팅이 일어나지 않은 것은 아니라는 의미이다.

  • 왜냐하면 선언은 정말 끌어올려진 것이 맞다.(정확히는 선언이 코드 실행 전에 메모리에 저장되었다는 의미.)
  • 그런데 왜 오류가 날까? -> var키워드는 선언과 함께 undefined로 초기화되어 메모리에 저장되는데 let,const는 초기화되지 않은 상태로 선언만 메모리에 저장되기 때문이다. 즉, let,const를 썻을때는 메모리에 선언만 저장되고 undefined조차로도 초기화되어있지 않은 상태!
  • 초기화 되지 않으면 변수를 참조할 수 없다.그래서 참조 에러 발생!
  • let,const에도 호이스팅이 일어나기 때문에 참조 에러를 일으키는 것이다.

호이스팅이 현상을 의미하는것 이기에 let 키워드에서도 상단으로 끌어올려진 것 같은 현상

즉, 호이스팅이 발생했기 때문에 에러가 발생한다.(에러가 난다고 호이스팅이 아닌게 아닌, 호이스팅이 발생했기에 에러가 발생한 것이다.)

변수는 어떻게 생성되고 호이스팅은 어떻게 이루어질까?

  • 변수는 3단계에 걸쳐 생성됨.

1단계 : 선언 단계

  • 변수를 실행 컨텍스트의 변수 객체에 등록.
  • 이 변수 객체는 스코프가 참조하는 대상이 된다.
  • 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.

2단계 : 초기화 단계

  • 식별자에 암묵적으로 undefined 값 바인딩.
  • 이 단계에서 변수는 undefined로 초기화 된다.

3단계 : 할당 단계

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

var키워드로 선언한 변수는 선언 단계와 초기화 단계가 한번에 이루어짐.
즉, 스코프에 변수를 등록(선언 단계)하고 초기화 단계에서 메모리에 변수를 위한 공간을 확보 후, undefined로 초기화! 따라서 변수 선언문 이전에 변수를 참조하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않음. 단, undefined를 반환함. 이후 할당 단계에 도달하면 비로소 값이 할당된다.

let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행됨. 즉, 스코프에 변수를 등록(선언 단계)하지만 초기화 단계는 변수 선언문에 도달했을 때(코드 실행 후) 이루어진다. 초기화 이전에 변수에 접근하려고 하면 참조 에러 발생! 이는 아직 변수가 초기화되지 않았기 때문이다. 즉, 아무런 값이 없으니 유효한 값을 읽어 올 수 없다! 이다.

따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없다(선언 라인 이전에는 변수를 참조할 수 없다!). 스코프의 시작 지점 ~ 초기화 시작 지점까지의 구간일시적 사각지대(Temporal Dead Zone; TDZ)라고 부른다.


호이스팅 예시

->

A(); // 함수 선언문에서는 끌어올려져서 가장 상단에서 선언한 것처럼 잘 출력된다.
B(); // 참조 에러 발생!
function A() { // 함수 선언문
  console.log('Hi');
}
let B = function() { // 함수 표현식
  console.log('BBB');
}
profile
개발 재밌다

0개의 댓글

Powered by GraphCDN, the GraphQL CDN