킹갓제네럴
거지같은 JS 문법 파헤치기 - 호이스팅,TDZ(변수가 왜 거기서 나와?) 본문
면접에서 많이 나오는 호이스팅..
호이스팅은 var, let, const별로 다르게 동작합니다.
얘네는 호이스팅 뿐만 아니라 스코프도 다르게 지정되니,
스코프 먼저 공부해야 헷갈리지 않을거에요
사전 지식 : 변수 할당 순서
변수가 선언되면 기본적으로 3단계를 거칩니다.
1. 선언(declaration) : 메모리 공간 확보
2. 초기화(initialization) : 메모리 공간을 undefined로 할당
3. 할당(assignment) : 개발자가 원하는 값을 할당
1, 2번의 시점은 JS엔진에 의해 결정되고, 이것이 호이스팅의 영향을 받습니다.
3번의 시점은 개발자가 해당 코드를 적어놓은 시점입니다.
var의 호이스팅
console.log(a); // ReferenceError: a is not defined
존재하지 않는 변수를 참고하면 에러가 발생하는 것이 인지상정이죠
console.log(a); // undefined
var a = 1;
console.log(a); // 1
그런데 이 미친 자바스크립트는 위의 코드에서 에러를 발생시키지 않습니다.
왜냐하면 var는 변수 선언(declaration)을 항상 스코프 최상단에서 수행하기 때문이죠
세부 순서를 본다면 아래와 같습니다.
// [변수 선언] : a의 메모리 공간 확보
// [변수 초기화] : a를 undefined로 초기화
console.log(a); // undefined
var a = 1; // [변수 할당] : a에 1 할당
console.log(a); // 1
이와 같이 [변수 선언]과 [변수 초기화]가 스코프 최상단으로 올라가서 실행되는 것을 호이스팅이라고 합니다.
변수가 여러 개 있더라도 아래와 같이 동작합니다.
// [변수 선언] : a, b의 메모리 공간 확보
// [변수 초기화] : a, b를 undefined로 초기화
console.log(a); // undefined
console.log(b); // undefined
var a = 1; // [변수 할당] : a에 1 할당
var b = 2; // [변수 할당] : b에 2 할당
console.log(a); // 1
console.log(b); // 2
누구나 이걸 보면 뭔 이상한 정책을 만들어놨냐고 욕할겁니다.
가독성도 떨어지고 언젠가 오류가 날 게 뻔해 보이죠
JS도 이걸 알았는지, ES6에서 let, const를 통해 해결책을 내놓습니다.
let의 호이스팅
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 1;
console.log(a); // 1
let은 할당 이전 변수의 참조를 막아놨습니다.
어 그러면 호이스팅이 이제 없어진건가요?
- 네 아닙니다.(여전히 존재)
// [변수 선언] : a의 메모리 공간 확보
let a = 1; // [변수 초기화 & 할당] : a를 undefined로 초기화 한 후, 1을 할당
console.log(a); // 1
위와 같이 초기화 시점을 밑으로 끌어내린 것 뿐입니다 : 스코프 최상단 -> 할당 직전
그러면 [변수 선언]과 [변수 초기화] 사이에 틈이 생기게 되는데,
이 구간을 TDZ(Temporal Dead Zone)라고 부릅니다.
TDZ에서 변수를 참조하면 ReferenceError가 발생하는거죠
const의 호이스팅
const는 간단하게 [변수 선언], [변수 초기화], [변수 할당]이 무조건 동시에 발생합니다.
console.log(a) // ReferenceError: Cannot access 'a' before initialization
const a = 1; // [변수 선언&초기화&할당]
console.log(a) // 1
그리고 재할당이 금지되기 때문에 상수처럼 쓸 수 있다는 특징이 있죠
추가
JS엔진은 hoisting될 변수를 어떻게 알고있나요?
JS엔진은 소스코드를 실행하기 전에 평가 과정을 거칩니다.
따라서 코드 실행 전에, 블록 내부에 있는 모든 변수를 끌어모아 호이스팅 하기 때문에
호이스팅과 런타임은 관련이 없습니다.
자세한건 제일 마지막에 퀴즈 2번을 참고하세요
재선언
var는 재선언이 허용됩니다.
console.log(a); // undefined
var a = 1;
console.log(a); // 1
var a = 2;
console.log(a); // 2
[변수 선언]과 [변수 초기화]는 호이스팅되고,
var a = 1; 시점에서는 [변수 할당]만 진행되니,
이미 선언되었든 아니든 JS엔진은 알빠가 아니죠
다만 let과 const는 재선언이 불가능합니다.
let a = 1;
console.log(a);
let a = 2; // SyntaxError: Identifier 'a' has already been declared
console.log(a);
퀴즈
1번 문제 : let의 스코프와 호이스팅을 이해했나요?
let a = 1;
{
console.log(a); // 결과값은?
let a = 2;
}
정답 : ReferenceError: Cannot access 'a' before initialization
let으로 선언된 변수는 블록 스코프를 따르고, 그 스코프의 최상단에서 호이스팅이 발생합니다.
// [변수 선언] : outer a의 메모리 확보
let a = 1; // [변수 초기화 & 할당] : outer a를 초기화 및 1 할당
{
// [변수 선언] : inner a의 메모리 확보
console.log(a); // inner a를 TDZ에서 참조 -> 에러
let a = 2; // [변수 초기화 & 할당] : inner a를 초기화 및 2 할당
}
2번 문제 : var의 스코프와 호이스팅을 이해했나요?
console.log(a);
if (false) {
var a = 1;
}
console.log(a);
정답 : undefined, undefined
var로 선언된 변수는 함수 스코프를 따라 if블록을 무시합니다.
따라서 호이스팅에 의해 [변수 선언], [변수 초기화]가 발생하지만,
[변수 할당]은 런타임에서 발생하지 않습니다.
// [변수 선언 & 초기화] : a의 메모리 공간 확보 및 undefined로 초기화
console.log(a);
if (false) {
var a = 1; // [변수 할당] : if문에 의해 실행되지 않음
}
console.log(a);
'개발 > 자바스크립트' 카테고리의 다른 글
거지같은 JS 문법 파헤치기 - 스코프(변수는 어디에서 와서 언제 가는가) (0) | 2024.12.31 |
---|---|
거지같은 JS 문법 파헤치기 - var, let, const 차이점 (0) | 2024.12.31 |