simoong·blog

쉽게 이해하는 자바스크립트 클로저(Closure)

image

쉽게 이해하는 자바스크립트 클로저(Closure)

자바스크립트 클로저(Closure) 는 면접에서 자주 나오고 실무에서도 정말 많이 쓰이는 개념이에요.
이번 글에서는 클로저의 정의 → 기본 예제 → 실무 활용 → 주의할 점 → 추가 학습까지 하나씩 차근차근 살펴볼게요.


📌 클로저란 무엇인가요?

클로저는 "함수와 그 함수가 선언될 당시의 렉시컬 환경(Lexical Environment)의 조합" 을 말해요.
즉, 함수가 자신이 선언된 스코프의 변수를 기억하고, 함수 실행이 끝난 뒤에도 그 변수에 접근할 수 있는 거예요.

function outerFunction() {
    let outerVariable = 'I am outer!'
 
    function innerFunction() {
        console.log(outerVariable)
    }
 
    return innerFunction
}
 
const myClosure = outerFunction()
myClosure() // 출력: I am outer!

위 코드에서 innerFunction은 이미 outerFunction 실행이 끝난 뒤 호출되지만, 여전히 outerVariable에 접근할 수 있어요.
👉 이게 바로 클로저의 매력이에요!


📌 클로저의 주요 활용 사례

1. Private 변수 만들기 (데이터 숨기기)

function createCounter() {
    let count = 0
 
    return function () {
        count++
        console.log(count)
    }
}
 
const increment = createCounter()
increment() // 1
increment() // 2
increment() // 3

외부에서 count를 직접 바꿀 수 없으니 안전하게 상태를 관리할 수 있어요.


2. 상태 유지 (State Preservation)

function userSession(userId) {
    let loginCount = 0
 
    return {
        login: function () {
            loginCount++
            console.log(`${userId}의 로그인 횟수: ${loginCount}`)
        },
        getLoginCount: function () {
            return loginCount
        },
    }
}
 
const sessionA = userSession('userA')
sessionA.login() // userA의 로그인 횟수: 1
sessionA.login() // userA의 로그인 횟수: 2
console.log(sessionA.getLoginCount()) // 2

👉 로그인 세션, API 호출 횟수 제한 같은 기능에 잘 어울려요.


3. 함수 팩토리 (Function Factory)

function greeter(name) {
    return function () {
        console.log(`Hello, ${name}!`)
    }
}
 
const greetJohn = greeter('John')
const greetJane = greeter('Jane')
 
greetJohn() // Hello, John!
greetJane() // Hello, Jane!

👉 버튼별 맞춤 동작 정의, 사용자별 메시지 생성 등에 자주 쓰여요.


4. 커링(Currying) 구현

function multiply(a) {
    return function (b) {
        return a * b
    }
}
 
const double = multiply(2)
const triple = multiply(3)
 
console.log(double(5)) // 10
console.log(triple(5)) // 15

👉 할인율 계산, 단위 변환기 같은 상황에서 편리해요.


📌 클로저 사용할 때 주의할 점

  1. 메모리 누수 조심!
    필요 없는 변수를 계속 들고 있으면 메모리를 낭비할 수 있어요.

  2. 성능 저하 가능성
    클로저는 스코프 체인을 따라가므로 과도하게 쓰면 성능이 떨어질 수 있어요.

  3. 디버깅 어려움
    값이 어디서 바뀌었는지 헷갈릴 수 있어요.
    → 크롬 개발자 도구(DevTools)에서 Closure 확인 기능을 활용해 보세요.


❓ 클로저와 자주 나오는 인터뷰 질문

  • 자바스크립트에서 클로저란 무엇인가요?
  • 클로저를 활용해 private 변수를 어떻게 구현하나요?
  • 클로저가 메모리 관리에 어떤 영향을 줄 수 있나요?
  • 클로저와 스코프(Scope)의 차이는 무엇인가요?

👉 이런 질문은 면접에서 정말 자주 나와요. 미리 예제 코드를 준비해 두면 좋아요!


⚖️ 클로저와 다른 개념 비교

  • 스코프(Scope): 변수가 유효한 범위를 의미해요.
  • 렉시컬 환경(Lexical Environment): 코드가 작성될 당시의 변수 환경이에요.
  • 클로저(Closure): 스코프와 렉시컬 환경을 함수가 기억해서 실행되는 거예요.
  • this: 실행 시점의 객체를 가리키는 키워드예요. 클로저와는 별개랍니다.

⚠️ 클로저 잘못 쓰는 경우 (Anti-Pattern)

for (var i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i)
    }, 1000)
}
// 출력: 3, 3, 3

👉 var를 쓰면 클로저 때문에 의도치 않게 같은 값이 출력돼요.
✅ 해결 방법: let을 사용하거나 IIFE(즉시 실행 함수)로 감싸 주세요.

for (let i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i)
    }, 1000)
}
// 출력: 0, 1, 2

📌 클로저 실무 활용 예시 모음

  • 웹 로그인 세션 관리
  • 이벤트 핸들러 내부 상태 기억
  • API 호출 제한기 (Rate Limiter)
  • React/Vue 커스텀 훅에서 상태 유지
function rateLimiter(limit, interval) {
    let calls = 0
    let start = Date.now()
 
    return function () {
        const now = Date.now()
        if (now - start > interval) {
            start = now
            calls = 0
        }
 
        if (calls < limit) {
            calls++
            console.log('API 요청 허용돼요!')
            return true
        } else {
            console.log('요청이 제한됐어요!')
            return false
        }
    }
}
 
const limitedAPI = rateLimiter(3, 5000)
 
limitedAPI() // API 요청 허용돼요!
limitedAPI() // API 요청 허용돼요!
limitedAPI() // API 요청 허용돼요!
limitedAPI() // 요청이 제한됐어요!

📚 추가 학습 자료


✅ 마무리

자바스크립트 클로저는 데이터 숨기기, 상태 유지, 함수 만들기, 성능 최적화 등 여러 상황에서 강력한 무기예요.
하지만 무분별하게 쓰면 오히려 메모리 낭비와 성능 저하가 생길 수 있으니 주의해야 해요.

👉 클로저를 잘 이해하고 적절하게 활용하면, 여러분의 코드가 훨씬 더 깔끔해질거에요! 🎉

쉽게 이해하는 자바스크립트 클로저(Closure) · Simoong Blog