hoist:(흔히 밧줄이나 장비를 이용하여) 들어[끌어]올리다
🐣 Hoisting- MDN
JavaScript 호이스팅은 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트(import)의 선언문을 해당 범위의 맨 위로 끌어올리는 것처럼 보이는 "현상"을 뜻합니다.
자바스크립트 엔진은 코드를 실행하기 전 실행 가능 한 코드를 형상화 하고 구분하는 과정(*실행 컨텍스트)을 거칩니다.
*실행 컨텍스트: 실행 가능한 코드가 실행되기 위해 필요한 환경
자바스크립트 엔진은 실행 컨텍스트의 과정에서 모든 선언 (var, let, const, function, class) 를 스코프에 등록합니다.
*스코프: 식별자(변수, 함수, 클래스) 가 유효한 범위
자바스크립트 엔진이 스코프를 통해 어떤 변수를 참조할 지 결정하기 때문에, 식별자를 검색할 때 사용하는 규칙
코드가 실행되기 전, 스코프에 변수, 함수 선언이 저장되었기 때문에 선언문보다 참조/호출이 나와도 오류없이 동작합니다.
🐣 변수 호이스팅 (var, let, const)
자바스크립트의 모든 선언에는 호이스팅이 일어나지만, let, const, class 를 이용한 선언문 에서는 호이스팅이 일어나지 않은 것 처럼 동작합니다.
// 스코프의 선두에서 선언 단계와 초기화 단계가 실행된다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 있다.
console.log(foo); // undefined
var foo;
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
위와 같이 var 의 경우 선언과 함께 undefined 로 초기화 되어 메모리에 저장됩니다.
// 스코프의 선두에서 선언 단계가 실행된다.
// 아직 변수가 초기화(메모리 공간 확보와 undefined로 초기화)되지 않았다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined
let foo; // 변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
하지만 let 의 경우 에러를 일으키는데요, 이는 호이스팅 되지 않은 것이 아니라 초기화 되지 않은 상태로 선언만 메모리에 저장되었기 때문 입니다.
초기화 되지 않으면 변수를 참조할 수 없어, 참조 에러가 발생합니다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: foo is not defined
let foo = 2; // 지역 변수
}
위 예시의 경우 전역변수인 foo 값이 출력 될 것으로 보였으나, 참조 에러가 발생하였습니다.
let으로 선언한 변수는 블록 레벨 스코프를 가지므로 코드 블록 내에서 선언된 변수 foo 는 지역변수 입니다.
따라서 지역변수 foo 도 해당 스코프에서 호이스팅 되고 블록의 시작부터 초기화가 이루어 지기까지 일시적 사각지대 (TDZ)에 빠집니다.
따라서 전역변수 foo 값이 출력되지 않고 참조 에러가 발생합니다.
🐣 변수의 생성 단계
1. 선언 단계 (Declaration Phase)
- 변수를 실행 컨텍스트의 변수 객체에 저장합니다.
- 이 변수 객체는 스코프가 참조하는 대상이 됩니다.
2. 초기화 단계 (Initialization Phase)
- 변수 객체 공간에 등록된 변수를 위한 메모리 공간을 확보합니다.
- 이 단계에서 변수는 undefined로 초기화 됩니다.
3. 할당 단계 (Assignment Phase)
- undefined로 초기화 한 변수에 실제 값을 할당합니다.
🐣 함수 선언에서의 호이스팅 예시
foo1(); // 함수 선언문에서는 호이스팅 일어난다.
foo2(); // 함수 표현식이라서 호이스팅 안된다.
function foo1() {
console.log('Hello');
}
var foo2 = function() {
console.log('world');
}
🐣 번외) var vs. let vs. const
변수 선언에는 기본적으로 const를 사용하고 let은 재할당이 필요한 경우에 한정해 사용하는 것이 좋다. 원시 값의 경우, 가급적 상수를 사용하는 편이 좋다. 그리고 객체를 재할당하는 경우는 생각보다 흔하지 않다. const 키워드를 사용하면 의도치 않은 재할당을 방지해 주기 때문에 보다 안전하다.
- ES6를 사용한다면 var 키워드는 사용하지 않는 것이 좋다.
- 재할당에 필요한 경우에 한정에 let 키워드를 사용한다. 이때 스코프는 최대한 좁게 만든다.
- 변경이 발생하지 않는 (재할당이 필요 없는 상수) 원시 값과 객체에는 const 키워드를 사용한다. const 키워드는 재할당을 금지하므로 var, let 보다 안전하다.
변수를 선언한 시점에 재할당이 필요한지 판단하는 경우는 드물다. 그렇기 때문에 변수를 선언할 때에 일단 const 키워드를 사용하자. 반드시 재할당이 필요하다면 그때 const 를 let 키워드로 변경하도록 하자
'새발지식' 카테고리의 다른 글
null 과 undefined 의 차이를 아세요? (2) | 2024.01.08 |
---|