변수의 생명 주기와 함수가 기억하는 것들, 그리고 현대 개발에서의 중요성
자바스크립트 개발자라면 스코프(Scope)와 클로저(Closure)라는 단어를 한 번쯤은 들어보셨을 겁니다. 이 두 개념은 자바스크립트가 변수를 다루고 코드를 실행하는 방식의 가장 기본적인 토대가 됩니다. 모던 웹 개발에서 React, Vue, Angular 같은 프레임워크를 사용하거나, 비동기 코드를 다룰 때, 효율적인 자바스크립트 코드를 작성하기 위해 이 개념들을 깊이 이해하는 것이 필수적입니다.
1. 스코프(Scope)란 무엇인가?
자바스크립트에서 스코프(Scope)는 변수가 어디까지 유효하고 접근 가능한지를 정하는 규칙이라고 생각하시면 됩니다. 즉, 변수의 '활동 범위'를 정해주는 것이죠.
크게 두 가지 주요 스코프가 있습니다.
- 전역 스코프 (Global Scope): 코드의 어디에서든 접근 가능한 변수들의 범위입니다. 한번 선언되면 프로그램이 끝날 때까지 살아있습니다.
// 전역 변수
const globalVar = '저는 전역 변수입니다.';
function accessGlobal() {
console.log(globalVar); // 함수 내부에서도 전역 변수 접근 가능
}
accessGlobal(); // "저는 전역 변수입니다." 출력
console.log(globalVar); // 함수 외부에서도 전역 변수 접근 가능
// "저는 전역 변수입니다." 출력
- 지역 스코프 (Local Scope): 특정 함수 안에서만 접근 가능한 변수들의 범위입니다. 함수가 실행될 때 만들어지고, 함수 실행이 끝나면 보통 사라집니다.
function myFunction() {
// 함수 스코프 변수 (지역 변수)
const localVar = '저는 지역 변수입니다.';
console.log(localVar); // 함수 내부에서 접근 가능
}
myFunction(); // "저는 지역 변수입니다." 출력
console.log(localVar);
// 에러 발생! ReferenceError: localVar is not defined
// 함수 외부에서는 지역 변수에 접근할 수 없습니다.
보시는 것처럼 전역 변수 globalVar
는 어디서든 쓸 수 있지만, 지역 변수 localVar
는 myFunction
함수 안에서만 사용할 수 있어요. 이게 바로 스코프의 역할입니다.
2. 클로저(Closure)란 무엇인가?
그럼 클로저(Closure)는 뭘까요? 클로저는 함수가 만들어질 때, 그 함수를 둘러싸고 있는 외부 스코프의 변수들을 기억하고 접근할 수 있는 기능을 가진 함수를 말합니다.
좀 더 쉽게 말하면, 클로저는 외부 함수의 실행이 끝났는데도 불구하고, 그 외부 함수 안에 있던 변수들을 여전히 사용할 수 있는 특별한 함수입니다. 이건 자바스크립트에서 제공하는 아주 강력한 기능 중 하나입니다.
클로저는 보통 데이터를 외부로부터 숨기거나 (데이터 은닉), 혹은 특정 상태 값을 계속 유지하고 싶을 때 유용하게 사용됩니다.
2.1 기본적인 클로저 예시
function createCounter() {
let count = 0; // 외부 함수의 변수 (클로저에 의해 '기억'됨)
// 내부 함수 (클로저)를 반환
return function () {
count = count + 1; // 외부 함수의 'count' 변수에 접근하여 변경
console.log(count);
};
}
// createCounter()를 호출하면, count 변수를 포함하는 클로저가 반환됩니다.
const counter1 = createCounter();
const counter2 = createCounter(); // 새로운 클로저, 자신만의 count를 가집니다.
console.log('--- 첫 번째 카운터 ---');
counter1(); // 1 출력
counter1(); // 2 출력
counter1(); // 3 출력
console.log('--- 두 번째 카운터 ---');
counter2(); // 1 출력 (counter1과는 독립적인 count 변수를 가짐)
counter2(); // 2 출력
createCounter
함수가 실행을 마치면count
변수는 원래 사라져야 합니다.- 하지만
createCounter
가 반환한 내부 익명 함수는 여전히count
변수를 사용하고 있습니다. - 자바스크립트는 내부 함수가 외부 스코프의 변수를 참조하고 있음을 감지하고, 해당
count
변수를 메모리에서 제거하지 않습니다. - 이렇게
createCounter
가 반환한 내부 함수가count
변수(외부 환경)를 '기억'하고 접근할 수 있는 현상을 클로저라고 합니다. counter1
과counter2
는 각각createCounter
를 호출할 때 생성된 서로 다른 클로저이므로, 자신만의 독립적인count
변수를 가집니다.
2.2 클로저를 활용한 정보 은닉(Private Variables)
클로저는 자바스크립트에 내장된 '프라이빗' 변수 개념이 없던 시절, 정보를 은닉하는 데 널리 사용되었습니다.
function createBankAccount(initialBalance) {
let balance = initialBalance; // 클로저에 의해 보호되는 '프라이빗' 변수
return {
// 잔액을 반환하는 메서드
getBalance: function () {
console.log(`현재 잔액: ${balance}원`);
return balance;
},
// 입금하는 메서드
deposit: function (amount) {
if (amount > 0) {
balance += amount;
console.log(`${amount}원 입금. 새로운 잔액: ${balance}원`);
} else {
console.log('유효하지 않은 입금액입니다.');
}
},
// 출금하는 메서드
withdraw: function (amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
console.log(`${amount}원 출금. 새로운 잔액: ${balance}원`);
} else if (amount > balance) {
console.log('잔액이 부족합니다.');
} else {
console.log('유효하지 않은 출금액입니다.');
}
},
};
}
const myAccount = createBankAccount(10000); // 초기 잔액 10000원
myAccount.getBalance(); // 현재 잔액: 10000원
myAccount.deposit(5000); // 5000원 입금. 새로운 잔액: 15000원
myAccount.withdraw(3000); // 3000원 출금. 새로운 잔액: 12000원
console.log(myAccount.balance);
// undefined 출력! balance 변수에 직접 접근할 수 없습니다.
// 오직 반환된 메서드를 통해서만 balance를 조작할 수 있습니다.
myAccount.withdraw(15000); // 잔액이 부족합니다.
createBankAccount
함수 내부에 선언된balance
변수는 외부에서는 직접 접근할 수 없습니다.- 하지만
getBalance
,deposit
,withdraw
같은 내부 함수들은balance
변수에 접근할 수 있습니다. - 이 내부 함수들이 클로저를 형성하여
balance
변수를 캡처하고 유지합니다. - 이를 통해
balance
는 외부로부터 보호되는 '프라이빗' 변수처럼 동작하며, 오직 이 함수들이 제공하는 메서드를 통해서만 안전하게 조작될 수 있습니다.
오늘은 스코프와 클로저를 알아봤습니다. 스코프와 클로저 는 자바스크립트가 변수를 관리하고 함수가 동작하는 방식의 핵심 개념입니다. 이 두 개념을 잘 이해하면 복잡한 자바스크립트 코드를 만들 때 더 효과적으로 작업할 수 있어요. 특히 클로저는 데이터를 안전하게 다루는 중요한 패턴을 구현할 때 도움이 됩니다. 도움이 되셨길 바랍니다 :)
'Front-End > Javascript' 카테고리의 다른 글
자바스크립트: 클린 코드 (2) | 2025.06.04 |
---|---|
자바스크립트: 작업 처리 방식의 두 얼굴 (동기와 비동기) (2) | 2025.05.29 |