프로그래밍/Javascript

자바스크립트 클로저(Closure): 개념부터 실전 활용까지 완벽 가이드

shimdh 2025. 2. 14. 09:33
728x90

클로저란 무엇인가?

자바스크립트를 배우다 보면 "클로저(Closure)"라는 개념이 자주 등장합니다. 이는 함수형 프로그래밍과 객체지향 프로그래밍에서 모두 중요한 개념이며, 코드의 모듈화, 데이터 보호(은닉), 상태 유지 등의 기능을 제공합니다. 클로저를 제대로 이해하고 활용하면 보다 유지보수하기 쉬운 코드와 성능 최적화가 가능해집니다.

이 글에서는 클로저의 개념과 동작 원리, 실전 활용법, 그리고 사용 시 주의할 점까지 깊이 있게 다뤄보겠습니다.


🔍 클로저의 개념

1. 클로저란?

클로저(Closure)란 "함수와 그 함수가 선언된 렉시컬 환경(Lexical Environment)을 함께 저장하고 유지하는 기능"을 의미합니다.

즉, 내부 함수가 외부 함수의 변수를 기억하고, 외부 함수 실행이 끝난 이후에도 해당 변수에 접근할 수 있는 구조를 클로저라고 합니다.

2. 왜 클로저가 중요한가?

자바스크립트는 함수 기반 언어이며, 클로저를 활용하면 다음과 같은 장점을 얻을 수 있습니다.

  • 데이터 은닉(Data Hiding): 외부에서 접근할 수 없는 변수나 상태를 유지할 수 있음
  • 상태 유지(State Persistence): 함수 실행이 끝난 후에도 변수를 기억하여 값의 지속성을 유지
  • 메모리 효율성: 필요한 데이터만 유지하면서 불필요한 전역 변수 사용을 줄임
  • 콜백 함수와 이벤트 핸들링: 비동기 프로그래밍 및 고차 함수에서 유용하게 활용 가능

🏗️ 클로저의 동작 방식

1. 기본적인 클로저 예제

클로저를 이해하기 위해 다음 코드를 살펴보겠습니다.

function outerFunction() {
    let outerVar = "나는 외부 변수입니다!";

    function innerFunction() {
        console.log(outerVar); // 내부 함수에서 외부 변수 접근 가능
    }

    return innerFunction;
}

const closureExample = outerFunction(); 
closureExample(); // 출력: 나는 외부 변수입니다!

📝 코드 설명

  1. outerFunction 내부에서 outerVar 변수를 선언합니다.
  2. innerFunctionouterVar을 참조합니다.
  3. outerFunction 실행이 끝난 후에도 innerFunctionouterVar을 유지합니다.
  4. closureExample()을 실행하면 outerVar에 접근하여 값을 출력합니다.

즉, 외부 함수 실행이 끝난 후에도 내부 함수가 외부 변수에 접근할 수 있는 것이 클로저의 핵심입니다.


🎯 클로저의 실전 활용

1. 상태 유지 (State Persistence)

클로저를 사용하면 함수 실행 후에도 변수를 지속적으로 유지할 수 있습니다.

function makeCounter() {
    let count = 0; // 상태 유지 변수

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

const counter = makeCounter();
console.log(counter()); // 출력: 1
console.log(counter()); // 출력: 2
console.log(counter()); // 출력: 3

💡 실전 활용 예:

  • 방문자 카운트
  • 게임 내 점수 유지
  • 폼 입력값 캐싱

2. 데이터 은닉 및 캡슐화

클로저를 사용하면 외부에서 직접 변경할 수 없는 데이터를 만들 수 있습니다.

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

const secretHolder = createSecretHolder(123);
console.log(secretHolder.getSecret()); // 출력: 123
secretHolder.setSecret(456);
console.log(secretHolder.getSecret()); // 출력: 456

💡 실전 활용 예:

  • 비밀번호 저장 (예: JWT 토큰)
  • 사용자 설정값 유지

3. 이벤트 핸들링

클로저를 활용하면 특정 이벤트 리스너 내부에서 변수를 유지할 수 있습니다.

function buttonHandler() {
    let count = 0;

    return function() {
        count++;
        console.log(`버튼 클릭 횟수: ${count}`);
    };
}

const button = document.querySelector("#myButton");
const handleClick = buttonHandler();

button.addEventListener("click", handleClick);

💡 실전 활용 예:

  • 클릭 이벤트 횟수 추적
  • UI 애니메이션 상태 유지

⚠️ 클로저 사용 시 주의할 점

1. 메모리 누수 (Memory Leak)

클로저는 함수 실행 후에도 변수 값을 유지하므로, 불필요한 데이터가 메모리에 남아 있을 수 있음에 주의해야 합니다.

function createLargeClosure() {
    let largeArray = new Array(1000000).fill("데이터"); 

    return function() {
        console.log(largeArray.length);
    };
}

const closure = createLargeClosure();
// closure가 사용되지 않으면 largeArray는 메모리에 남아 있음

🔧 해결 방법:

  • 클로저 내 변수를 필요할 때만 유지하도록 설계
  • 필요하지 않으면 변수에 null 할당

2. 성능 저하 (Performance Issues)

클로저는 메모리를 계속 차지하므로, 불필요하게 많이 사용하면 성능이 저하될 수 있습니다.

function heavyOperation() {
    let data = new Array(1000000).fill("불필요한 데이터");

    return function() {
        console.log("작업 완료");
    };
}

🔧 해결 방법:

  • 클로저를 꼭 필요한 경우에만 사용
  • WeakMap 등을 활용하여 메모리 관리

🏁 결론

클로저는 자바스크립트에서 데이터 은닉, 상태 유지, 성능 최적화 등의 다양한 패턴을 구현하는 데 필수적인 개념입니다.

클로저의 핵심 포인트

  • 내부 함수가 외부 함수의 변수에 접근할 수 있다.
  • 함수 실행 후에도 변수를 유지할 수 있다.
  • 데이터 은닉, 캡슐화, 이벤트 핸들링 등에 활용할 수 있다.
  • 메모리 누수 및 성능 저하를 방지하기 위해 주의가 필요하다.

클로저를 제대로 이해하고 활용하면 더 효율적이고 안전한 자바스크립트 코드를 작성할 수 있습니다! 🚀

728x90