프로그래밍/Javascript

클로저와 렉시컬 스코프: 자바스크립트의 강력한 개념과 실전 활용법

shimdh 2025. 2. 14. 11:51
728x90

자바스크립트는 매우 유연한 언어이며, 다양한 방식으로 코드를 작성하고 구조화할 수 있습니다. 그중에서도 클로저(Closure)렉시컬 스코프(Lexical Scope) 는 자바스크립트에서 핵심적인 개념으로, 함수 내부에서 외부 변수를 어떻게 접근하고 관리하는지를 결정하는 중요한 원칙입니다.

이 개념들을 깊이 이해하면 유지보수하기 쉬운 코드를 작성할 수 있을 뿐만 아니라, 비동기 프로그래밍과 같은 고급 기능을 효과적으로 활용할 수 있습니다. 이번 글에서는 렉시컬 스코프와 클로저의 개념을 살펴보고, 실전에서 어떻게 적용할 수 있는지 다양한 사례와 함께 알아보겠습니다.


🔹 렉시컬 스코프(Lexical Scope): 변수가 유효한 범위를 결정하는 원리

렉시컬 스코프란, 변수의 유효 범위(Scope)가 코드가 작성된 위치(정의된 위치)에 따라 결정된다는 개념입니다. 즉, 함수가 어디에서 실행되는지가 아니라, 어디에서 선언되었는지가 변수를 접근하는 방식에 영향을 줍니다.

📌 예제 코드: 렉시컬 스코프의 기본 원리

function outerFunction() {
    let outerVariable = '나는 바깥에 있어요!';

    function innerFunction() {
        console.log(outerVariable); // "나는 바깥에 있어요!" 출력
    }

    return innerFunction;
}

const myInnerFunction = outerFunction();
myInnerFunction(); // 호출 시 outerVariable에 접근 가능

위 코드에서 innerFunctionouterFunction 내부에 선언되었으며, outerFunction의 변수 outerVariable에 접근할 수 있습니다.
이것이 가능한 이유는 자바스크립트의 렉시컬 스코프 때문으로, innerFunction이 선언될 때 자신이 속한 스코프(상위 함수의 변수 포함)를 기억하기 때문입니다.

🔹 렉시컬 스코프의 핵심 특징:

  • 스코프는 실행 시점이 아니라 선언 시점에서 결정된다.
  • 내부 함수는 자신이 선언된 환경(상위 함수)의 변수에 접근할 수 있다.
  • 함수가 호출된 위치와 관계없이, 선언된 위치를 기준으로 변수 접근 방식이 결정된다.

🔹 클로저(Closure): 외부 상태를 기억하는 함수

클로저(Closure)함수가 생성될 당시의 외부 변수 및 환경을 기억하고, 나중에도 해당 변수에 접근할 수 있도록 해주는 기능 을 의미합니다.
이 개념은 함수가 실행된 후에도 기존 환경을 유지할 수 있도록 해주며, 데이터 은닉 및 상태 유지 등의 다양한 프로그래밍 패턴을 가능하게 합니다.

📌 예제 코드: 클로저의 동작 방식

function makeCounter() {
    let count = 0; // 외부 변수 (private variable)

    return function() { 
        count += 1; 
        return count; 
    };
}

const counter1 = makeCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2

const counter2 = makeCounter();
console.log(counter2()); // 1 (새로운 카운터)

이 코드에서 makeCounter 함수는 실행될 때마다 새로운 count 변수를 가진 클로저를 반환합니다.
counter1, counter2는 서로 다른 count 변수를 유지하며 독립적인 상태를 가질 수 있습니다.
즉, 클로저를 활용하면 외부에서 직접 변수에 접근할 수 없도록 보호하면서도, 특정 로직을 수행할 때 내부 상태를 유지할 수 있습니다.


🔹 클로저의 실용적인 활용 사례

✅ 1. 데이터 은닉 (Encapsulation)

클로저를 사용하면 특정 데이터를 외부에서 직접 변경할 수 없도록 보호 할 수 있습니다.
이를 통해 정보 은닉(Information Hiding) 이 가능하며, 보안성이 향상된 코드를 작성할 수 있습니다.

function createSecretHolder(secret) {
    return {
        getSecret: function() { return secret; },
        setSecret: function(newSecret) { secret = newSecret; }
    };
}

const secretHolder = createSecretHolder('비밀 정보');
console.log(secretHolder.getSecret()); // "비밀 정보"
secretHolder.setSecret('새로운 비밀');
console.log(secretHolder.getSecret()); // "새로운 비밀"

위 코드에서는 secret 변수가 외부에서 직접 접근되지 않으며, getSecretsetSecret 메서드를 통해서만 조작할 수 있습니다.
이는 객체 지향 프로그래밍의 캡슐화(Encapsulation) 개념과 유사한 효과 를 제공합니다.


✅ 2. 함수 팩토리 (Function Factory)

클로저를 사용하면 특정 설정을 가진 여러 함수를 동적으로 생성할 수 있습니다.

function greetingGenerator(greeting) {
    return function(name) {
        console.log(`${greeting}, ${name}!`);
    };
}

const sayHello = greetingGenerator('안녕하세요');
const sayHi = greetingGenerator('반가워요');

sayHello('철수'); // "안녕하세요, 철수!"
sayHi('영희');    // "반가워요, 영희!"

이처럼 클로저를 사용하면 공통적인 로직을 포함하면서도, 다양한 맞춤형 함수를 손쉽게 생성할 수 있습니다.


✅ 3. 이벤트 핸들러에서의 활용

웹 개발에서는 클로저를 이용하여 이벤트 핸들러 내부에서 변수를 유지 할 수 있습니다.

function attachEventHandlers() {
    let count = 0;

    document.getElementById('myButton').addEventListener('click', function() {
        count += 1;
        console.log(`버튼이 ${count}번 클릭되었습니다.`);
    });
}

attachEventHandlers();

여기서 count 변수는 attachEventHandlers 함수가 실행될 때 생성되지만, 이후에도 이벤트 핸들러 내부에서 계속 유지됩니다.
즉, 버튼이 클릭될 때마다 count 값이 증가하며, 이를 클로저 덕분에 추적할 수 있습니다.


🔹 결론: 클로저와 렉시컬 스코프를 이해하면 코드가 쉬워진다

자바스크립트에서 클로저와 렉시컬 스코프는 함수의 동작 방식과 변수를 다루는 방법을 이해하는 핵심 개념 입니다.
이 개념들을 익히면 효율적인 코드 구조를 만들고, 데이터를 안전하게 보호하며, 다양한 패턴을 활용한 동적인 기능을 구현할 수 있습니다.

🚀 핵심 정리:

✔️ 렉시컬 스코프: 함수가 선언될 때의 위치에 따라 변수의 유효 범위가 결정된다.
✔️ 클로저: 함수가 생성될 당시의 외부 환경을 기억하여, 실행이 끝난 후에도 해당 변수를 유지할 수 있다.
✔️ 활용 사례: 데이터 은닉, 함수 팩토리, 이벤트 핸들러 등 다양한 프로그래밍 패턴에서 유용하게 사용된다.

728x90