[JavaScript] 스코프(Scope), 스코프체인(Scope Chain), 호이스팅(Hoisting)
1. 스코프(Scope)
스코프란 변수나 함수가 유효하게 사용될 수 있는 범위를 정의하는 개념.
쉽게 말해, 코드에서 특정 변수나 함수가 "어디서" 접근될 수 있는지 결정하는 규칙.
종류
- 전역 스코프 (Global Scope): 전역 변수는 모든 함수나 코드에서 접근 가능.
- 함수 스코프 (Function Scope): 함수 내에서 선언된 변수는 해당 함수 내부에서만 유효.
- 지역 스코프 (Local Scope): 함수 내에서 let이나 const로 선언된 변수는 해당 함수나 코드 블록 내에서만 유효.
- 블록 스코프 (Block Scope): {}로 구분되는 블록 내에서만 유효한 변수로, let과 const로 선언된 변수는 블록 내에서만 접근 가능.
- 어휘적 스코프 (Lexical Scope): 함수의 스코프는 함수가 정의된 위치에 따라 결정되며, 실행 시점이 아니라 코드 작성 시점에 결정.
예시 코드
1. 전역 스코프 (Global Scope)
전역에서 선언된 변수는 프로그램의 어느 곳에서든 접근할 수 있다.
let globalVar = "I'm a global variable"; // 전역 변수
function showGlobalVar() {
console.log(globalVar); // 전역 변수에 접근
}
showGlobalVar(); // "I'm a global variable"
console.log(globalVar); // "I'm a global variable"
변수 globalVar는 전역 스코프에 선언되었으므로, 함수 내부와 외부 어디서든 접근할 수 있다.
2. 함수 스코프 (Function Scope)
var로 선언된 변수는 함수 스코프를 따다. 함수 외부에서는 접근할 수 없다.
function exampleFunction() {
var localVar = "I'm a function-scoped variable"; // 함수 내에서 선언된 변수
console.log(localVar); // 함수 내에서는 사용 가능
}
exampleFunction(); // "I'm a function-scoped variable"
console.log(localVar); // ReferenceError: localVar is not defined
변수 localVar는 함수 스코프 내에서만 유효하며, 함수 외부에서는 접근할 수 없다.
3. 지역 스코프 (Local Scope)
함수 내부에서 let이나 const로 선언된 변수는 지역 스코프를 가진다. 이는 해당 블록 내에서만 유효하다.
function localScopeExample() {
let localVar = "I'm a block-scoped variable"; // 지역 변수
console.log(localVar); // 함수 내에서 사용 가능
}
localScopeExample(); // "I'm a block-scoped variable"
console.log(localVar); // ReferenceError: localVar is not defined
localVar는 지역 스코프로 선언되어 localScopeExample 함수 내에서만 사용 가능하다.
4. 블록 스코프 (Block Scope)
let이나 const로 선언된 변수는 블록 내에서만 유효하며, if, for와 같은 블록 구조에서도 동작한다.
if (true) {
let blockVar = "I'm a block-scoped variable"; // 블록 내에서 선언된 변수
console.log(blockVar); // "I'm a block-scoped variable"
}
console.log(blockVar); // ReferenceError: blockVar is not defined
변수 blockVar는 블록 {} 내에서만 유효하다. 블록 외부에서는 참조할 수 없다.
5. 어휘적 스코프 (Lexical Scope)
함수의 스코프는 함수가 선언된 위치에 의해 결정된다. 실행 시점이 아니라 코드 작성 시점에 결정된다.
function outerFunction() {
let outerVar = "I'm an outer variable"; // 외부 함수 변수
function innerFunction() {
console.log(outerVar); // 외부 함수의 변수에 접근
}
innerFunction(); // "I'm an outer variable"
}
outerFunction();
// console.log(outerVar); // ReferenceError: outerVar is not defined
innerFunction은 outerFunction 내에 선언되었기 때문에, outerVar에 접근할 수 있다. 이는 어휘적 스코프 덕분이다.
정리
- 전역 스코프는 모든 코드에서 접근 가능하다.
- 함수 스코프는 var로 선언된 변수들이 해당 함수 내에서만 유효하다.
- 지역 스코프는 let이나 const로 선언된 변수들이 함수나 블록 내에서만 유효하다.
- 블록 스코프는 {}로 감싸진 블록 내에서만 유효한 변수이다.
- 어휘적 스코프는 함수의 스코프가 함수 선언 시점에 결정되며, 함수가 선언된 위치에 따라 스코프가 결정된다.
💡스코프 체인 (Scope Chain)
- 💡스코프 체인 (Scope Chain)
- 스코프 체인은 변수 검색의 규칙을 말한다. JavaScript는 변수를 찾을 때 현재 스코프에서 해당 변수를 찾고, 만약 없다면 그 위에 있는 스코프를 검색하는 방식으로 동작합니다. 이 과정을 스코프 체인이라고 부른다.
- 예시 코드
let globalVar = "I'm a global variable";
function outer() {
let outerVar = "I'm an outer variable";
function inner() {
let innerVar = "I'm an inner variable";
console.log(innerVar); // "I'm an inner variable"
console.log(outerVar); // "I'm an outer variable"
console.log(globalVar); // "I'm a global variable"
}
inner();
}
outer();
inner 함수는 innerVar, outerVar, globalVar 순서대로 스코프 체인을 통해 변수를 찾아 출력한다. inner에서 변수를 찾지 못하면 그 상위 스코프인 outer에서, 그 역시 못 찾으면 전역 스코프인 globalVar를 찾아 접근한다.
💡호이스팅 (Hoisting)
- 💡 호이스팅 (Hoisting)
- 예시코드
var x = 5;에서 x는 선언만 호이스팅되기 때문에, 변수 x는 undefined로 출력된다. 할당(= 5)은 실제 코드 실행 시점에서 이루어지기 때문에 x의 값은 여전히 undefined이다. 하지만, hoistedFunction()은 함수 선언 전체가 호이스팅되어 호출 가능하다.console.log(x); // undefined var x = 5; hoistedFunction(); // "This function is hoisted!" function hoistedFunction() { console.log("This function is hoisted!"); }
- 호이스팅은 변수와 함수 선언이 실행 코드보다 먼저 올라가는 특성을 말한다. 하지만 변수에 대한 값 할당은 호이스팅되지 않는다.
let과 const는 호이스팅되지만, 초기화가 이루어지기 전에는 사용할 수 없다. 이를 TDZ(Temporal Dead Zone)라고 부른다.
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;
- let y = 10;에서 y는 호이스팅되어 메모리에는 선언이 되지만, 값이 할당되는 시점까지는 "초기화되지 않은 상태"로 남아 있다.
- console.log(y);가 실행되기 전에 y가 초기화되지 않았기 때문에 TDZ에 해당하는 영역에서 y를 참조하려고 하면 ReferenceError가 발생한다.
- TDZ을 피하는 방법
-
정상적으로 초기화된 후에는 변수에 접근하자!let y = 10; console.log(y); // 10
var와의 차이점
- var는 호이스팅될 때 초기화도 함께 일어나기 때문에, var 변수를 선언하기 전에 접근하면 undefined가 반환된다.
console.log(x); // undefined
var x = 10;
let과 const는 선언은 호이스팅되지만 초기화는 코드가 실행될 때 이루어지므로,
초기화되기 전까지는 변수에 접근할 수 없다. 이 부분이 TDZ와 관련된 차이점이다.