1. 정의
인터프리터가 변수와 함수의 메모리 공간을 선언하기 전에 미리 할당하는 것을 의미한다. 쉽게 말해서 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는 자바스크립트 고유의 특징이다.
console.log(a); //undefined
var a = 1;
// 에러가 나지않고 undefined가 나온다.
코드를 위에서 아래로 읽으면서 아직 나오지 않은 a를 불러오는데 에러가 나지 않는다. 이미 a라는 변수는 선언되었고, var a= 1 라인에 와서야 a 변수에 1을 할당하는 것이다.
2. 소스코드
'이미 변수가 선언되었다'는 내용을 이해하기 위해 소스코드를 읽어오는 순서에 대해 알아보았다. 자바스크립트 엔진은 소스코드를 "소스코드의 평가"와 "소스코드의 실행" 과정으로 나누어 처리한다.
평가 과정에서 실행 컨텍스트를 생성하고 변수, 함수 등 선언문만 먼저 실행하여 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프에 등록한다.
평가 과정이 끝나면 선언문을 제외한 소스코드가 순차적으로 실행되는 런타임이 시작된다. 이때 변수나 함수의 참조를 실행 컨텍스트가 관리하는 스코프에서 검색하여 취득한다. 그리고 변수 값의 변경 등 소스코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록된다. 아래 코드를 예로 들어보자.
var x = 1;
// 위 코드는 var x; x=1; 두 단계로 나눠서 실행된다.
소스코드 평가과정에서 var x; 를 먼저 실행한다. 생성된 변수 식별자 x는 실행 컨텍스트가 관리하는 스코프에 등록되고, undefined로 초기화된다. 평가과정이 끝나고 실행 과정이 실행되면 var x;는 이미 실행이 완료되었기 때문에 x = 1; 만 실행된다.
따라서 변수 선언뿐 아니라 var, let, function, class 키워드를 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅된다. 모든 선언문은 런타임 이전 단계에서 먼저 실행되기 때문이다. 그중에서도 함수가 가장 먼저 실행된다.
// 런타임 전에 이미 x 변수 선언되어 있다.
console.log(x); //undefined
x = 1;
console.log(x) // 1
var x;
3. 함수 & 변수 호이스팅
함수 호이스팅은 가장 먼저 이루어지기 때문에 선언된 함수는 상단에서 참조, 호출이 가능하다. 즉 식별자가 변수 객체에 수집될 때 함수 참조에 대한 초기화까지 자동으로 이루어지는 것이다.
하지만 변수 호이스팅의 경우 var와 let, const를 구분해야 한다. var는 상단에서 참조, 할당이 가능하지만 let, const는 상단에서 참조, 할당이 불가능하다.
var는 호이스팅이 발생하면 선언과 초기화가 거의 동시에 일어나기 때문에, 변수 선언문 이전에 참조할 수 있다. (위 예제)
let, const는 마치 호이스팅이 발생하지 않는 것처럼 동작한다.
console.log(x)
let x;
//ReferenceError: Cannot access 'x' before initialization
이는 var와 달리 "선언 단계"와 "초기화 단계"가 분리되어 진행되기 때문이다. 즉 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
console.log(x) // ReferenceError: Cannot access 'x' before initialization
let x;
console.log(x); // undefined
x=1;
console.log(x); // 1
이처럼 let, const 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점(변수 선언문)까지 변수를 참조할 수 없는 데, 이 구간을 일시적 사각지대(Temporal Dead Zone; TDZ)라고 부른다. ES6에 도입된 let, const, class를 사용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다는 점에 유의해야 한다.
4. 결론
변수 호이스팅이 지양되는 이유는 값을 덮어쓰게 됨으로써 득 될 것이 없고 오류 발생 가능성을 높이기 때문이다. 이런 피해를 방지하고자 let과 const를 사용하게 되는데, TDZ 문제를 의식하고 있다면 처음부터 변수의 선언을 상단에 모아두는 방법이 있다. 자바스크립트의 엔진 특성상 컴파일을 거치며 자연스럽게 생기는 전처리 과정이니 다양한 사례를 접하고 반복해보면서 변수와 함수를 더 잘 사용하도록 하자
참조)
deep dive
https://developer.mozilla.org/ko/docs/Glossary/Hoisting
https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/
'Programing > Javascript' 카테고리의 다른 글
[JS] 소셜웹페이지 - 메인화면 (0) | 2022.08.06 |
---|---|
[JS] 소셜웹페이지 - 로그인 UI (0) | 2022.08.02 |
[JS] HTMLCollection & NodeList (0) | 2022.07.19 |
[JS] 이터러블과 유사 배열 객체 (0) | 2022.07.17 |
[JS] var vs. let vs. const (0) | 2022.07.15 |