호이스팅(Hoisting)은 자바스크립트에서 변수가 선언된 위치와 상관없이 해당 변수 선언이 코드의 최상단으로 끌어올려지는 동작을 의미합니다. 호이스팅은 변수 선언뿐만 아니라 함수 선언에도 적용됩니다. 다만, 변수의 초기화는 호이스팅되지 않으며, 변수 선언만 호이스팅됩니다. ( var가 아닌 let을 쓴다면 'ReferenceError' 발생! 이유는 ' TDZ ' 아래에서 다시 설명)
예를 들어, 아래와 같은 코드가 있을 때:
console.log(x); // undefined
var x = 5;
console.log(x); // 5
위의 코드는 실제로는 다음과 같이 동작합니다:
var x;
console.log(x); // undefined
x = 5;
console.log(x); // 5
즉, 변수 x의 선언이 코드의 최상단으로 끌어올려져서 console.log가 실행되기 전에 var x;가 미리 선언된 것과 같은 효과를 나타냅니다.
함수 선언도 호이스팅되므로, 다음과 같은 코드가 정상적으로 실행됩니다:
myFunction(); // Hello, world!
function myFunction() {
console.log('Hello, world!');
}
이 경우, 함수 myFunction의 선언이 코드의 최상단으로 끌어올려져서 함수 호출이 정상적으로 동작합니다.
하지만, 함수 표현식은 호이스팅되지 않기 때문에 아래와 같은 코드는 오류를 발생시킵니다:
myFunction(); // TypeError: myFunction is not a function
var myFunction = function() {
console.log('Hello, world!');
};
이 경우, 변수 myFunction의 선언은 호이스팅되지만, 초기화는 호이스팅되지 않기 때문에 함수 호출 시점에는 myFunction이 아직 정의되지 않은 상태가 됩니다.
let 키워드를 사용한 경우, 호이스팅은 발생하지만 Temporal Dead Zone(TDZ)로 인해 변수 선언 전에 해당 변수에 접근하려고 하면 참조 오류가 발생합니다. let의 호이스팅과 관련된 예제를 통해 다시 설명해드리겠습니다.
let은 TDZ를 가지고있지만 var은 TDZ가 없다!
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 5;
console.log(x); // 5
- 호이스팅 발생:
- 선언은 호이스팅되지만 초기화는 호이스팅되지 않습니다. 따라서 스코프의 최상단으로 끌어올려지지만 초기화되지 않은 상태로 존재합니다.
- Temporal Dead Zone(TDZ):
- 변수 선언이 호이스팅되더라도 해당 변수를 실제로 초기화하기 전까지는 변수에 접근할 수 없습니다. 이 구간을 TDZ라고 하며, TDZ 내에서 변수를 참조하면 ReferenceError가 발생합니다.
실제 동작 방식
위 예제는 내부적으로 다음과 같이 동작합니다:
// x는 선언되었지만 초기화되지 않은 상태로 TDZ에 있음
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x; // 변수 선언
x = 5; // 변수 초기화
console.log(x); // 5
추가 예제
블록 스코프 내에서 let 변수를 사용하는 경우도 보여드리겠습니다:
function testLet() {
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 10;
if (true) {
let a = 20;
console.log(a); // 20 (블록 내에서 유효한 a)
}
console.log(a); // 10 (함수 블록 내에서 유효한 a)
}
testLet();
이 예제는 다음과 같은 순서로 동작합니다:
- console.log(a)는 함수 블록 내에서 TDZ에 있는 a에 접근하려고 하므로 ReferenceError를 발생시킵니다.
- let a = 10;을 만나면서 a가 초기화됩니다.
- if 블록 내에서 새로운 블록 스코프를 가지는 a 변수가 선언되고 초기화됩니다.
- 내부 블록에서의 a는 20이며, 블록 밖의 a는 10입니다.
이와 같이, let을 사용하면 블록 스코프와 TDZ를 통해 더 안전하고 예측 가능한 코드를 작성할 수 있습니다.
참고사항
Python:
- Python에서는 호이스팅 개념이 존재하지 않습니다. 변수는 선언된 위치에서부터 유효하며, 미리 선언되지 않은 변수를 참조하면 NameError가 발생합니다.
print(x) # NameError: name 'x' is not defined
x = 5
print(x) # 5
Java:
- Java에서는 변수 선언과 초기화가 순차적으로 이루어져야 합니다. 미리 선언되지 않은 변수를 사용하면 컴파일 오류가 발생합니다.
public class Main {
public static void main(String[] args) {
System.out.println(x); // Compile Error: cannot find symbol
int x = 5;
System.out.println(x); // 5
}
}
C:
- C 언어에서는 변수를 사용하기 전에 반드시 선언해야 하며, 변수 선언은 보통 코드 블록의 맨 위에 위치시킵니다. 선언되지 않은 변수를 사용하면 컴파일 오류가 발생합니다.
#include <stdio.h>
int main() {
printf("%d\n", x); // Compile Error: 'x' undeclared
int x = 5;
printf("%d\n", x); // 5
return 0;
}
Ruby:
- Ruby에서는 변수는 선언 없이 사용될 수 있지만, 초기화되지 않은 변수는 nil 값을 가집니다. 함수 정의는 코드가 실행되는 순서에 영향을 받습니다.
puts x # nil
x = 5
puts x # 5
이처럼, 다른 프로그래밍 언어들은 변수와 함수 선언 및 초기화와 관련된 규칙이 자바스크립트와 다르며, 자바스크립트처럼 호이스팅이 발생하지 않습니다. 각 언어의 특성을 이해하고 사용하면 더 효과적으로 코드를 작성할 수 있습니다.
'웹개발 정보 > JavaScript' 카테고리의 다른 글
let 과 var의 차이 (0) | 2024.06.25 |
---|