자바스크립트의 스코프(Scope)와 클로저(Closure)는 실행 컨텍스트를 이해하는 데 필수적인 개념입니다. 이 글에서는 블록 스코프와 함수 스코프의 차이, 클로저의 정의와 동작 원리, 실제 사용 예시를 통해 초보자도 쉽게 이해할 수 있도록 체계적으로 설명합니다.
스코프와 클로저는 자바스크립트 실행 흐름의 본질이다
자바스크립트를 포함한 대부분의 프로그래밍 언어에서 스코프(Scope)와 클로저(Closure)는 코드의 실행 흐름과 변수의 유효 범위를 결정하는 매우 중요한 개념입니다. 스코프는 변수가 어디에서 선언되고, 어디까지 접근 가능한지를 규정하며, 클로저는 이 스코프의 개념을 바탕으로 함수를 선언한 위치에서의 환경을 기억하는 기능을 말합니다. 자바스크립트는 **렉시컬 스코프(Lexical Scope)**, 즉 정적 스코프를 따릅니다. 이는 함수가 어디서 호출되었는지가 아니라, 어디서 정의되었는지에 따라 상위 스코프가 결정된다는 의미입니다. 이로 인해 자바스크립트의 변수 접근 규칙은 다소 직관적이지 않게 느껴질 수 있으나, 스코프와 클로저를 정확히 이해하고 나면 코드의 실행 원리가 명확하게 보이게 됩니다. 또한 자바스크립트는 함수 기반의 스코프를 사용해 왔으며, ES6 이후에는 let과 const의 도입으로 블록 스코프도 적용됩니다. 이러한 구조적 차이를 이해하지 못하면 변수의 중복 선언, 참조 오류, 예기치 못한 값 변경 등의 문제를 겪기 쉽습니다. 이번 글에서는 스코프와 클로저의 개념을 기초부터 명확하게 정리하고, 이를 바탕으로 실제 자바스크립트 함수와 실행 흐름이 어떻게 작동하는지 구체적인 예제를 통해 설명합니다. 이를 통해 자바스크립트의 복잡한 동작 원리를 체계적으로 정립할 수 있습니다.
스코프의 종류와 클로저의 작동 원리
1. 함수 스코프(Function Scope) vs 블록 스코프(Block Scope)
자바스크립트에서 var로 선언된 변수는 함수 스코프를 따릅니다. 즉, 함수 내부에서만 유효하며 블록({}) 내에서 선언되었더라도 함수 바깥에서 접근이 가능합니다.
function test() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
반면 let과 const는 블록 스코프를 따르며, 선언된 블록 내부에서만 접근 가능합니다.
function test() {
if (true) {
let y = 20;
}
console.log(y); // ReferenceError
}
2. 렉시컬 스코프(Lexical Scope)
렉시컬 스코프란, 함수가 정의된 위치에서의 스코프 체인을 기준으로 상위 스코프가 결정되는 것을 의미합니다.
let a = 1;
function outer() {
let b = 2;
function inner() {
console.log(a + b); // 3
}
inner();
}
outer();
inner 함수는 outer 함수 안에서 정의되었기 때문에 outer의 스코프에 접근할 수 있으며, 이것이 렉시컬 스코프의 기본 개념입니다. 3. 클로저(Closure)의 정의
클로저는 함수가 선언될 당시의 환경(스코프)을 기억하는 함수입니다. 즉, 함수 외부에서 정의된 변수에 접근할 수 있는 내부 함수를 말하며, 외부 함수가 종료되어도 내부 함수가 해당 변수를 기억하고 계속 사용할 수 있습니다.
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
이 예제에서 내부 함수는 외부 함수의 지역 변수 count에 접근할 수 있으며, makeCounter가 종료된 후에도 count는 사라지지 않고 유지됩니다. 이것이 클로저의 작동 원리입니다. 4. 클로저의 활용 예
- 프라이빗 변수 만들기 - 이벤트 핸들러에서 외부 상태 기억하기 - setTimeout/setInterval 콜백에서 값 유지하기 등
function createUser(name) {
return {
sayHello: function() {
console.log("안녕하세요, " + name + "입니다.");
}
};
}
const user1 = createUser("홍길동");
user1.sayHello(); // 안녕하세요, 홍길동입니다.
이처럼 클로저는 특정 값이나 상태를 숨기고 캡슐화하는 데 매우 유용하게 사용됩니다.
스코프와 클로저는 자바스크립트 이해의 중심축
스코프와 클로저는 자바스크립트의 실행 방식과 메모리 구조를 이해하는 데 핵심적인 역할을 합니다. 변수에 언제 어디서 접근할 수 있는지를 결정하는 스코프의 개념은 코드의 안정성과 예측 가능성에 직결되며, 클로저는 이 스코프를 기반으로 외부 상태를 기억하는 매우 강력한 기능입니다. 많은 초보 개발자들이 클로저를 어렵게 느끼지만, 결국 클로저는 렉시컬 스코프의 연장선에 불과합니다. 함수가 어디서 호출되었는지가 아니라, 어디서 정의되었는지를 기준으로 변수 참조가 이루어지며, 이 원리를 이해하면 클로저 또한 자연스럽게 이해할 수 있습니다. 실무에서는 클로저를 이용해 프라이빗 변수나 상태를 유지하거나, 비동기 처리 중에 상태가 유지되는 구조를 만들 수 있습니다. 하지만 클로저가 메모리 누수의 원인이 될 수 있다는 점도 유의해야 하며, 필요하지 않은 클로저는 생성하지 않는 것이 좋습니다. 결론적으로, 스코프와 클로저는 자바스크립트의 핵심 개념 중 하나로, 단순히 변수의 유효 범위를 넘어서 함수의 실행 방식, 상태 관리, 메모리 처리에 이르기까지 광범위하게 영향을 미치는 요소입니다. 이 두 개념을 정확히 이해하고 활용할 수 있다면 자바스크립트를 한층 더 깊이 있게 다룰 수 있는 개발자가 될 수 있습니다.