호이스팅(hoisting)
호이스팅은 자바스크립트에서 특별한 동작 원리를 지칭한다. 많이 오해하는 바와 달리, 호이스팅은 변수나 함수의 선언을 물리적으로 코드의 최상단으로 이동시키는 것이 아니라, 선언을 스코프의 최상단에 위치한 것처럼 자바스크립트 엔진이 해석하는 현상을 말한다.
- 호이스팅 정의: 자바스크립트에서 선언(변수, 함수 등)을 코드 상단에 위치한 것처럼 엔진이 처리하는 현상.
- 물리적 이동 없음: 실제로 코드의 위치가 변경되는 것이 아니라, 자바스크립트 엔진이 선언을 코드 실행 전에 먼저 인식함.
- 실행 컨텍스트 생성: 코드 실행 전, 스코프 내의 모든 선언을 스코프 최상위에 있는 것처럼 처리하는 과정의 일부.
- var와 함수 선언의 호이스팅: var로 선언된 변수와 함수 선언문은 선언 전 참조/호출해도 오류가 발생하지 않음.
- let과 const의 특별한 경우: let, const로 선언된 변수는 호이스팅 되지만, 일시적 사각지대(Temporal Dead Zone, TDZ)에 의해 선언 전 참조 시 오류 발생.
- 실용적 이해: 호이스팅 이해는 코드의 동작 방식을 명확히 파악하고, 오류를 방지하는 데 도움을 줌.
var, let, const 의 차이점
- var: 선언과 동시에 undefined로 초기화된다. 이 때문에 선언 전 참조해도 undefined가 반환되며, 에러가 발생하지 않는다.
- let, const: 선언은 되지만, 초기화는 선언문에 도달했을 때 이루어진다. 초기화 전에 참조하려 하면 참조 에러(ReferenceError)가 발생하고, 이 구간을 '일시적 사각지대(Temporal Dead Zone, TDZ)'라고 한다.
호이스팅 과정
- 선언 단계: 실행 컨텍스트의 변수 객체에 변수를 등록한다. 이 변수 객체가 스코프의 참조 대상이 된다.
- 초기화 단계: 메모리에 변수를 위한 공간을 확보하고, 변수를 undefined로 초기화한다. (단, let과 const는 이 단계에서 초기화되지 않는다.)
- 할당 단계: 실제 값을 변수에 할당.
모든 변수 선언은 호이스팅된다. 단, var는 선언과 초기화가 동시에 이루어지고, let과 const는 선언 후 별도로 초기화되며, 초기화 전 접근 시 에러가 발생한다.
let과 const도 호이스팅이 일어나지만, TDZ 때문에 선언 전에 접근하면 에러가 발생한다. var로 선언된 변수는 호이스팅으로 인해 선언 전 참조해도 에러 없이 undefined가 반환되지만, let과 const는 TDZ에 의해 에러가 발생한다.
예시코드
❗️ 유효 범위와 스코프 - 사전지식
1. 함수 스코프: var로 선언된 변수는 함수 블록 내에서만 유효하다.
2. 블록 스코프: let, const로 선언된 변수는 중괄호 {}로 감싸진 블록 내에서만 유효하다.
function exampleFunction() { var functionScoped = "저는 함수 안에서만 존재해요!"; if (true) { var stillFunctionScoped = "저도 함수 안이면 어디든지 있을 수 있어요!"; let blockScoped = "저는 이 블록 안에서만 존재해요!"; const anotherBlockScoped = "저도 이 블록 안에서만요!"; } console.log(functionScoped); // 출력됨 console.log(stillFunctionScoped); // 출력됨 console.log(blockScoped); // 에러: blockScoped는 정의되지 않았습니다. console.log(anotherBlockScoped); // 에러: anotherBlockScoped는 정의되지 않았습니다. } exampleFunction();
예제1) 'var' 를 사용한 호이스팅 예시
console.log(myVar); // undefined 출력
var myVar = 'Hello World!';
console.log(myVar); // 'Hello World!' 출력
- var로 선언된 변수는 호이스팅으로 인해 선언이 코드 상단으로 끌어올려진다. (끌어올려지는 현상.)
- 초기화(undefined로 설정)도 선언과 함께 이루어지므로, 첫 번째 console.log에서 에러가 발생하지 않고 undefined가 출력된다.
예제2) 'let'을 사용한 호이스팅 예시
let test = 1; // 전역 변수 foo 선언 및 할당
{
console.log(test); // TDZ 에러 발생
let test = 2; // 블록 스코프 내 새로운 foo 선언 및 할당
}
- 전역 변수 foo: 전역 스코프에서 foo는 1로 초기화됩니다.
- 블록 스코프: 중괄호 {} 안에서 foo를 2로 재선언.
- TDZ: 'console.log(foo);' 가 블록 스코프 내의 새 foo 선언 전에 실행되기 때문에, 이 시점에서 새 foo는 TDZ에 있다. TDZ 내에서 변수에 접근하려 하면 참조 에러가 발생
예제3) ' const '를 사용한 선언에서의 오류 예시
const myConst; // SyntaxError: Missing initializer in const declaration
myConst = 'Hello World!';
console.log(myConst); // 이 코드는 실행되지 않음
'const'로 선언된 변수는 반드시 선언과 동시에 초기화되어야 한다. 초기화 없이 선언만 하려고 하면 구문 에러(SyntaxError)가 발생한다.
예제4) 함수 선언에서의 호이스팅 예시
func1(); // 'Hello' 출력
func2(); // TypeError: func2 is not a function
function func1() {
console.log('Hello');
}
var func2 = function() {
console.log('world');
}
함수 선언문과 호이스팅
함수 선언문(function func1() { ... })은 호이스팅되어, 코드의 어느 곳에서든지 호출할 수 있다. 이는 JavaScript 엔진이 실행 전에 함수 선언을 메모리에 저장하기 때문, 따라서 func1(); 호출은 정상적으로 작동하여 'Hello'를 출력한다.
함수 표현식과 호이스팅
함수 표현식(var func2 = function() { ... };)의 경우, 변수 func2는 호이스팅되지만, 변수의 할당은 실행 흐름이 해당 라인에 도달했을 때 이루어진다. 즉, func2 변수는 호이스팅으로 인해 선언은 되어 undefined로 초기화되지만, func2에 함수가 할당되기 전에 func2 ();를 호출하려 하면 func2 는 아직 함수가 아닌 undefined 상태이다. 이로 인해 TypeError: func2 is not a function 오류가 발생한다.
'JavaScript' 카테고리의 다른 글
[JavaScript] BFcache란 ? (0) | 2024.09.09 |
---|---|
[JavaScript] 메모이제이션 (Memoization) (0) | 2024.01.01 |