JS/Javascript

[javascript] 클로저 (Closure)

ui-o 2023. 2. 25. 17:08
반응형

클로저(Closure)

  • '함수와 + 그 함수가 선언된 환경(변수들)의 조합을 의미
  • 함수가 생성될 당시의 외부 변수(환경)를 기억하고, 그 함수가 나중에 호출되더라고 그 변수들에 접근할 수 있는 함수
  • 함수가 자신이 필요로 하는 외부 데이터를 ‘숨겨서’ 기억하고, 필요할 때 꺼내 쓸 수 있게 하는 기능

✓ Clos → "Close" (sure) → "Sure" = 확실하게 "가까이 다가가서 확실하게 담아두는 것"

✓ liken : 카메라가 어떤 장면에 클로즈업해서 중요한 디테일(변수)을 찍음
    촬영이 끝나도, 그 장면은 사진(메모리) 안에 계속 저장
    원본 장면(함수 본문)은 사라졌지만, 사진 속 정보(변수 상태)는 계속 꺼내볼 수 있음


* 렉시컬 환경(Lexical Environment)

  • 함수가 만들어질 때 그 함수가 접근할 수 있는 변수와 함수들의 집합
  • 이 집합은 함수가 선언된 위치(코드상 위치)에 따라 정해져서, “렉시컬(lexical)” 즉, “코드 텍스트 기준”이라는 뜻
  • 쉽게 말해, 함수가 어디서 만들어졌느냐에 따라 변수 접근 범위가 결정된다라는 것을 의미

왜 클로저가 필요한가

  • 함수가 호출될 때마다 생성된 지역변수는 보통 함수가 종료되면 그 변수는 사라짐
  • 하지만 클로저를 이용하면 함수 밖에서도, 함수 종료 후에도 그 함수가 선언된 환경의 변수 값을 계속 사용할 수 있음. 
    함수가 종료된 후에도 변수를 유지하고 싶을 때 사용하는 개념
  • 따라서 상태(state)를 유지하거나, 외부 변수에 접근하는 기능을 만들 수 있음

클로저 동작 원리

  • 함수가 호출될 때마다 자바스크립트 엔진은 렉시컬 환경(변수 환경)을 생성
  • 이 환경에는 해당 함수가 접근할 수 있는 변수들이 저장됨
  • 내부 함수는 이 환경을 기억하고, 외부 함수의 환경에 접근할 수 있음
  • 그래서 외부 함수가 끝나도 내부 함수가 그 환경을 계속 참조하기 때문에 변수가 사라지지 않고 유지됨

클로저 함수(Closure Function)

  • 클로저의 원리를 사용해서 만든 실제 함수
  • 클로저를 생성하는 함수(내부에서 외부 변수에 접근하는 함수를 반환하거나 사용하는 함수)를 의미
  • 클로저 함수는 클로저를 가지고 있는 함수 혹은 클로저를 만드는 함수를 의미하는 경우가 많음
  • 클로저는 보통 외부 함수 안에 내부 함수를 선언하고, 그 내부 함수를 반환(return) 하거나 다른 곳에 전달해서 사용
  • 특징
    • 함수 안에 함수 존재
    • 내부 함수가 외부 변수 참조
    • 외부 함수가 끝나도 변수 유지

일반함수와 클로저 함수 비교

항목 일반함수 클로저 함수
변수 유지 실행 끝나면 변수 삭제 실행 끝나도 변수 유지
변수 재사용 매번 새로 생성 기존 변수 계속 사용
출력 예시 "Hello", "Hello" (항상 초기 상태) "Hello", "Hello" (같은 변수라 상태를 공유)
응용 가능성 상태 저장 불가 상태 저장, 카운터, 정보 은닉 등 가능

일반함수

  1. normal() 실행 → msg 변수가 메모리에 생성됨
  2. "Hello" 출력
  3. 실행 끝나면 msg 변수는 메모리에서 제거됨
  4. 다시 실행하면 새로운 msg 변수가 만들어짐 (이전 값은 사라짐)
function normal() {
  let msg = "Hello";
  console.log(msg);
}

normal(); // "Hello"
normal(); // "Hello"

클로저 함수

  1. outer() 실행 → msg 변수가 메모리에 생성됨
  2. inner 함수가 반환되면서, inner는 msg 변수를 참조하고 있음
  3. outer 실행은 끝났지만, msg는 inner가 참조하고 있으므로 메모리에서 안 사라짐
  4. fn()을 실행할 때마다 같은 msg를 사용
function outer() {
  let msg = "Hello";

  return function inner() {
    console.log(msg);
  };
}

const fn = outer(); // inner 반환
fn(); // "Hello"
fn(); // "Hello"

클로저의 용도

private 변수 만들기 (정보 은닉)

 

  • 클로저를 이용하면 외부에서 직접 접근할 수 없는 변수를 만들 수 있음
  • 함수 내부 변수는 외부에서 보이지 않지만, 내부 함수가 그 변수를 기억하며 조작 가능
function createCounter() {
  let count = 0;  // 외부에서 직접 접근 불가

  return {
    increment() {
      count++;
      console.log(count);
    },
    decrement() {
      count--;
      console.log(count);
    }
  };
}

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
console.log(counter.count); // undefined (직접 접근 불가)

/*
- count 변수는 외부에서 직접 접근할 수 없고, 오직 클로저로 연결된 함수들을 통해서만 조작 가능
- 이렇게 하면 변수 값을 안전하게 보호할 수 있음
*/

 


2. 상태 유지 (데이터 기억)

 

  • 함수가 호출되고 종료되어도, 클로저가 외부 변수의 상태를 기억해서 계속 사용할 수 있음.
  • 변수를 계속 기억하여 재사용 가능
  • 예를 들어, 누적 합계 계산, 사용자 입력 저장, 특정 설정값 유지 등.
function outer() {
  let count = 0; // outer 함수의 지역변수

  function inner() {
    count++;
    console.log(count);
  }

  return inner; // inner 함수를 반환
}

const counter = outer(); // outer 실행, inner 함수가 반환됨
counter(); // 1
counter(); // 2
counter(); // 3

/*
- outer 함수가 실행될 때 count 변수가 만들어짐
- outer 내부의 inner 함수가 count 변수에 접근 가능
- outer 함수 실행이 끝났어도, inner 함수가 count 변수를 계속 기억하고 있음
- 그래서 counter()를 호출할 때마다 count 값이 1씩 증가하면서 출력됨
*/

 

function createAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = createAdder(5); // 여기서 x = 5 로 '고정'
console.log(add5(2));        // 여기서 y = 2

/*
1.createAdder(5) 실행
- 매개변수 x에 5가 들어감
- 반환되는 함수 (y) => x + y가 클로저로 만들어짐
- 이 클로저 함수는 x를 기억하고 있음 (여기서는 5)

2. add5(2) 실행
- y에 2가 들어감
- 클로저 덕분에 x의 값(5)을 여전히 알고 있으므로 5 + 2 계산 가능

정리 
- x는 이미 createAdder를 호출할 때 결정되고, 그 값이 클로저로 유지됨
- y는 반환된 함수를 실행할 때마다 새로 들어오는 값
- 띠라서, add5는 사실상 "y에 5를 더하는 함수"가 된 것
*/

3. 함수형 프로그래밍과 고차 함수 활용

  • 클로저는 함수형 프로그래밍에서 고차 함수(함수를 반환하거나 인자로 받는 함수)를 구현하는 데 필수적임.
  • 동적으로 함수의 동작을 만들어내거나, 인자값을 미리 기억하는 함수(부분 적용 함수, 커링 등)를 쉽게 구현 가능.
function multiplier(factor) {
  return function (num) {
    return num * factor;
  };
}

const double = multiplier(2);
const triple = multiplier(3);

console.log(double(4)); // 8
console.log(triple(4)); // 12

반응형

'JS > Javascript' 카테고리의 다른 글

[javascript] 구조 분해 할당, 배열 구조 분해  (0) 2023.10.19
[javascript] 타이머(timer) 함수  (0) 2023.03.08
[함수] 중첩함수  (0) 2023.02.25
[Javascript] 화살표 함수(Arrow Function)  (0) 2023.02.25
[Javascript] 변수  (0) 2023.02.04