본문 바로가기
FE/JavaScript

[JavaScript] 클로저

by thedev 2023. 3. 27.

 

클로저

 


 

# 클로저(Closure)란

 

 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여, 만일 자신이 선언됐을 때의 스코프 밖에서 호출되어도 스코프에 접근할 수 있는 함수를 말한다. 클로저는 자바스크립트 고유의 개념이 아니라 함수형 프로그래밍 언어에 등장하는 보편적인 특성이다. 객체지향 프로그래밍과 함수형 프로그래밍을 모두 아우르는 개념이기에 매우 중요하다. 예시를 통해 알아보자.

 

function outer() {
  const x = 10;
  const inner = function () {
    console.log(x);
  };
  return inner;
}

const result = outer();
result(); // 10

 

 함수 outer는 내부함수 inner를 반환하고 난 뒤 콜스택에서 사라진다. outer의 실행 컨텍스트가 사라졌으므로 outer에 있는 변수 x 또한 더 이상 존재하지 않게 된다. 따라서 const result = outer(); 코드 이후에는 변수 x를 참조할 수 없을 것처럼 보인다. 하지만 위 코드를 실행해보면 10이라는 값이 반환된다. 즉, x라는 변수가 사라지지 않고 여전히 참조 가능한 값으로 존재하고 있는 것이다.

 이처럼 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있다. 즉, 함수A에서 선언한 변수 a를 내부함수B가 사용할 경우, 함수A의 실행 컨텍스트가 종료된 이후에도 변수 a는 사라지지 않고 접근할 수 있다. 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수. 이러한 함수를 클로저라고 한다.

 

 

# 클로저의 용도

 

 클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. 상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉하고, 특정 함수에게만 상태 변경을 허용하기 위해 사용한다. 또한, 전역 변수 사용을 억제할 수 있다.

 

function closure() {
  let cnt = 0;
  function cntPlus() {
    cnt = cnt + 1;
  }
  function cntPrint() {
    console.log(cnt);
  }
  return {
    cntPlus,
    cntPrint,
  };
}

const cntClosure = closure();
cntClosure.cntPlus();
cntClosure.cntPrint();

 

 변수 cnt는 클로저에 의해 참조되고 있기 때문에 자신의 변경된 최신 상태를 계속해서 유지할 수 있다. 또한, 클로저를 이용하면 전역 변수를 사용하지 않고도 상태를 관리할 수 있고 클로저 함수 내에서 선언된 변수 cnt는 외부에서 접근할 수 없다. 따라서 특정 함수에게만 상태 변경 허용됨으로써 예기치 않게 값이 건드려지는 상황을 미리 방지할 수 있다.

 


 

리액트의 useState가 생각난다 원리가 비슷해보임😮

 

 

참고 자료

책 '모던 자바스크립트 Deep Dive' 24장

책 '코어 자바스크립트' 5장

https://youtu.be/LL0DGc5pg7A

https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%ED%81%B4%EB%A1%9C%EC%A0%80