관리 메뉴

JAN's History

📚 클로저(Closure)란? 본문

Javascript

📚 클로저(Closure)란?

JANNNNNN 2024. 11. 2. 18:12

클로저는 하위함수(내부 함수)가 상위 함수보다 더 오래 살아남아, 상위 함수 변수에 접근할 수 있는 것을 의미해요. 일반적으로 함수가 실행되고 나면 그 함수의 Execution Context는 사라지지만, 클로저가 발생하면 상위 함수의 변수나 상태가 메모리에 유지되어 내부 함수에서 계속 사용할 수 있게 됩니다!✨ 이해하기 쉽도록 차근차근 예시를 통해 설명해볼게요!

📌 간단한 클로저 예시

function getNumber() {
  var number = 5; // 상위 함수의 변수
  function innerGetNumber() { // 하위 함수(내부 함수)
    return number; // 상위 함수의 변수에 접근
  }
  return innerGetNumber;
}

const runner = getNumber(); // getNumber의 실행이 끝났지만...
console.log(runner()); // 내부 함수가 상위 함수의 변수를 기억하고 있어요!

 

  1. getNumber 함수가 실행되면 number라는 변수가 생성돼요.
  2. innerGetNumber 함수는 number에 접근할 수 있어요.
  3. getNumber 함수는 innerGetNumber 함수를 실행하지 않고 그대로 반환했어요. 사진에서도 Call Stack에 getNumber가 없고 바로 innerGetNumber가 실행이 된 모습을 확인할 수 있죠?
  4. getNumber의 실행이 끝나도, runner()를 통해 innerGetNumber를 호출하면 number 변수에 여전히 접근할 수 있어요!

⭐ 이게 바로 클로저예요! 하위 함수가 상위 함수의 변수에 접근할 수 있는 "권한"을 가진 상태로 남아있는 것을 말해요.

📌 클로저가 유용한 상황

1. 데이터 캐싱

function cacheFunction() {
  var number = 10 * 10; // 오래 걸리는 계산이라고 가정

  function innerCacheFunction(newNum) {
    return number * newNum; // `number`를 계속 재사용
  }
  return innerCacheFunction;
}

const runner2 = cacheFunction(); // `number`를 기억하고 있는 `innerCacheFunction` 반환
console.log(runner2(10)); // 1000
console.log(runner2(20)); // 2000

 

 

  • cacheFunction이 처음 호출될 때, number를 계산하고 메모리에 저장해요.
  • 이후 runner2를 통해 innerCacheFunction을 여러 번 호출할 때마다 이미 계산된 number를 사용하니 메모리와 시간을 절약할 수 있어요!

2. 정보 은닉

function Dog(type, size) {
  this.type = type; // 공개적으로 접근 가능한 속성
  var _size = size; // private 속성 (클로저로 은닉)

  this.sayHello = function () {
    return `안녕하세요 저는 ${this.type}입니다. 저의 사이즈는 ${_size}입니다.`; // 클로저를 통해 `_size`에 접근
  }
}

const pome = new Dog('포메라니안', 'small');
console.log(pome.sayHello()); // '안녕하세요 저는 포메라니안입니다. 저의 사이즈는 small입니다.'

console.log(pome.type); // '포메라니안'
console.log(pome._size); // undefined, 외부에서 직접 접근 불가

 

 

  • Dog 객체를 통해 sayHello 메서드에서만 _size를 사용할 수 있고, 외부에서는 직접 _size에 접근할 수 없어요.(this가 없기 때문)
  • 이를 통해 데이터를 은닉하고, 외부에서 함부로 객체의 상태를 변경할 수 없게 만들 수 있어요.

🛠 중요한 포인트: 왜 클로저를 사용해야 할까?

1. 정보 은닉과 캡슐화

  • 클로저를 사용하면 외부에서 내부 데이터에 직접 접근하는 것을 방지할 수 있어요.
  • 클래스에서의 private 같은 역할을 자바스크립트에서 흉내 낼 수 있죠.

2. 데이터 캐싱과 메모리 관리

  • 클로저를 이용해 이전에 계산된 데이터를 저장하고 재사용함으로써, 성능 향상이 가능해요.
  • 한 번 계산된 결과를 메모리에 기억해두고 여러 번 사용할 수 있어요.

혼란스러운 부분: 클로저가 안 되는 경우는?

아래 코드를 볼게요:

function cacheFunction2() {
  var number = 99;

  function increment() {
    number++;
    return number;
  }

  return increment; // 실행하면 클로저가 안됨
}

const runner3 = cacheFunction2();
console.log(runner3()); // 100
console.log(runner3()); // 101

 

  • 이 코드에서는 number를 계속 증가시킬 수 있고, 이는 클로저가 잘 작동하는 예시예요.

하지만 만약 내부 함수가 실행되지 않고 바로 반환된다면 클로저가 제대로 작동하지 않아요.

function cacheFunction3() {
  var number = 99;

  function increment() {
    number++;
    return number;
  }

  return increment(); // 클로저가 아님, 함수를 실행해버렸기 때문!
}
console.log(cacheFunction3()); // 100
console.log(cacheFunction3()); // 100
  • 이 경우엔 클로저가 아니라 함수를 실행한 결과를 반환하므로 클로저의 특성이 사라집니다.

💡 요약

  • 클로저하위 함수가 상위 함수의 변수에 계속 접근할 수 있는 것.
  • 데이터 캐싱, 정보 은닉 등에 유용해요.
  • 클로저를 잘 활용하면 메모리 관리를 효율적으로 할 수 있고, 코드의 안정성을 높일 수 있어요! 😊