13장. 스코프와 호이스팅
스코프 (Scope)란?
스코프(Scope)는 변수나 함수에 접근할 수 있는 범위를 의미합니다. JavaScript에는 여러 종류의 스코프가 있습니다.
1. 스코프의 종류
전역 스코프 (Global Scope)
함수나 블록 밖에서 선언된 변수는 전역 스코프를 가집니다.
let globalVar = '전역 변수';
function test() {
console.log(globalVar); // 접근 가능
}
console.log(globalVar); // 접근 가능
함수 스코프 (Function Scope)
함수 내부에서 선언된 변수는 함수 스코프를 가집니다.
function test() {
let functionVar = '함수 변수';
console.log(functionVar); // 접근 가능
}
// console.log(functionVar); // ReferenceError (접근 불가)
블록 스코프 (Block Scope)
let과 const는 블록 스코프를 가집니다.
if (true) {
let blockVar = '블록 변수';
console.log(blockVar); // 접근 가능
}
// console.log(blockVar); // ReferenceError (접근 불가)
2. var, let, const의 스코프
var: 함수 스코프
function test() {
if (true) {
var x = 10;
}
console.log(x); // 10 (블록을 무시하고 함수 스코프)
}
// console.log(x); // ReferenceError (함수 밖에서는 접근 불가)
let, const: 블록 스코프
function test() {
if (true) {
let y = 10;
const z = 20;
}
// console.log(y); // ReferenceError
// console.log(z); // ReferenceError
}
스코프 비교 예제
// var: 함수 스코프
function test1() {
for (var i = 0; i < 3; i++) {
// ...
}
console.log(i); // 3 (접근 가능)
}
// let: 블록 스코프
function test2() {
for (let j = 0; j < 3; j++) {
// ...
}
// console.log(j); // ReferenceError (접근 불가)
}
3. 스코프 체인 (Scope Chain)
변수를 찾을 때 현재 스코프에서 시작하여 상위 스코프로 올라가며 찾습니다.
let global = '전역';
function outer() {
let outerVar = '외부';
function inner() {
let innerVar = '내부';
console.log(innerVar); // '내부' (현재 스코프)
console.log(outerVar); // '외부' (상위 스코프)
console.log(global); // '전역' (전역 스코프)
}
inner();
}
outer();
4. 호이스팅 (Hoisting)이란?
호이스팅(Hoisting)은 변수와 함수 선언이 코드의 최상단으로 끌어올려지는 것처럼 동작하는 JavaScript의 특징입니다.
var의 호이스팅
console.log(x); // undefined (오류가 아님!)
var x = 10;
위 코드는 다음과 같이 동작합니다:
var x; // 선언이 끌어올려짐
console.log(x); // undefined
x = 10;
let, const의 호이스팅
// console.log(y); // ReferenceError (TDZ)
let y = 10;
// console.log(z); // ReferenceError (TDZ)
const z = 20;
let과 const도 호이스팅되지만, TDZ(Temporal Dead Zone) 때문에 선언 전에 접근할 수 없습니다.
5. 함수 호이스팅
함수 선언 (Function Declaration)
함수 선언은 완전히 호이스팅됩니다.
sayHello(); // ✅ 동작함!
function sayHello() {
console.log('Hello');
}
위 코드는 다음과 같이 동작합니다:
function sayHello() { // 함수 선언이 끌어올려짐
console.log('Hello');
}
sayHello(); // ✅ 동작함!
함수 표현식 (Function Expression)
함수 표현식은 호이스팅되지 않습니다.
// sayHi(); // ❌ TypeError
const sayHi = function() {
console.log('Hi');
};
sayHi(); // ✅ 동작함
화살표 함수
화살표 함수도 호이스팅되지 않습니다.
// sayBye(); // ❌ ReferenceError
const sayBye = () => {
console.log('Bye');
};
sayBye(); // ✅ 동작함
6. 호이스팅 예제
예제 1: var의 호이스팅
console.log(a); // undefined
var a = 10;
console.log(a); // 10
예제 2: let의 TDZ
// console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(b); // 20
예제 3: 함수 선언 호이스팅
test(); // ✅ "함수 실행됨"
function test() {
console.log('함수 실행됨');
}
예제 4: 함수 표현식은 호이스팅 안 됨
// test2(); // ❌ TypeError: test2 is not a function
var test2 = function() {
console.log('함수 실행됨');
};
test2(); // ✅ "함수 실행됨"
7. 스코프와 클로저 (Closure)
클로저(Closure)는 내부 함수가 외부 함수의 변수에 접근할 수 있는 현상입니다.
function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
const counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3
클로저 활용 예제
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
8. var의 문제점과 let/const 사용
var의 문제점
// 문제 1: 함수 스코프만 인식
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3 (예상과 다름!)
}, 100);
}
// 문제 2: 중복 선언 가능
var x = 10;
var x = 20; // 오류 없이 덮어씀
// 문제 3: 호이스팅으로 인한 혼란
console.log(y); // undefined (오류가 아님!)
var y = 10;
let/const 사용 (권장)
// 해결 1: 블록 스코프
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 0, 1, 2 (올바름!)
}, 100);
}
// 해결 2: 중복 선언 불가
let x = 10;
// let x = 20; // SyntaxError
// 해결 3: TDZ로 명확한 오류
// console.log(y); // ReferenceError
let y = 10;
9. 실전 예제
예제 1: 스코프 체인
let global = '전역';
function level1() {
let level1Var = '레벨 1';
function level2() {
let level2Var = '레벨 2';
function level3() {
let level3Var = '레벨 3';
console.log(level3Var); // '레벨 3'
console.log(level2Var); // '레벨 2'
console.log(level1Var); // '레벨 1'
console.log(global); // '전역'
}
level3();
}
level2();
}
level1();
예제 2: 클로저로 프라이빗 변수
function createBankAccount(initialBalance) {
let balance = initialBalance; // 프라이빗 변수
return {
deposit: function(amount) {
balance += amount;
return balance;
},
withdraw: function(amount) {
if (amount <= balance) {
balance -= amount;
return balance;
} else {
return '잔액 부족';
}
},
getBalance: function() {
return balance;
}
};
}
const account = createBankAccount(1000);
console.log(account.getBalance()); // 1000
console.log(account.deposit(500)); // 1500
console.log(account.withdraw(200)); // 1300
// console.log(balance); // ReferenceError (직접 접근 불가)
주의사항
1. 전역 변수 남용
// ❌ 전역 변수 남용
var x = 10;
var y = 20;
var z = 30;
// ✅ 객체로 묶기
const config = {
x: 10,
y: 20,
z: 30
};
2. var 대신 let/const 사용
// ❌ var 사용
for (var i = 0; i < 3; i++) {
// ...
}
// ✅ let 사용
for (let i = 0; i < 3; i++) {
// ...
}
3. 호이스팅 이해
// 호이스팅으로 인한 혼란 방지
// 함수는 선언 후에 호출하는 것이 좋음
function test() {
// ...
}
test(); // 선언 후 호출
연습 문제
- 스코프 이해
- 다음 코드의 출력 결과를 예상하세요:
let x = 10; function test() { let x = 20; console.log(x); } test(); console.log(x);
- 다음 코드의 출력 결과를 예상하세요:
- 호이스팅 이해
- 다음 코드의 출력 결과를 예상하세요:
console.log(a); var a = 10;
- 다음 코드의 출력 결과를 예상하세요:
- 클로저 활용
- 카운터 함수를 만들어서 호출할 때마다 숫자가 증가하도록 하세요.
- 스코프 체인
- 3단계 중첩 함수를 만들고, 각 레벨의 변수에 접근하는 코드를 작성하세요.
다음 장 예고
다음 장에서는 실습 문제를 통해 지금까지 배운 내용을 종합적으로 활용합니다.
'FrontEnd > Javascript' 카테고리의 다른 글
| JavaScript DOM과 이벤트 완전 정복 (1) | 2026.02.06 |
|---|---|
| 14장. 실습 문제 (0) | 2026.01.13 |
| 12장. 이벤트 (Event) (0) | 2026.01.11 |
| 11장. DOM 조작 (0) | 2026.01.10 |
| 10. 객체 (0) | 2026.01.09 |