꾸준한 개발자

계속적인 성장을 추구하는 개발자입니다. 꾸준함을 추구합니다.

계속 쓰는 개발 노트

JAVASCRIPT/자바스크립트 이론

클로저란

gold_dragon 2021. 1. 29. 16:13

MDN에서는 클로저를 다음과 같이 정의합니다.

 

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).

 

(번역) 클로저는 주변 상태 (렉시컬 환경)에 대한 참조와 함께 번들로 묶인 (포함된) 함수의 조합입니다.

 

위 정의만으로는 이해가 쉽게 되지 않습니다. 다음 예제를 보겠습니다.

const a = 1;

function outerFunc() {
  const a = 2;
  
  function innerFunc() {
    console.log(a); // 2
  }
  
  innerFunc();
}

outerFunc();

outerFunc 함수 내부에서 중첩 함수 innerFunc를 정의하고 호출하였습니다. 이때 중첩 함수 innerFunc의 상위 스코프는 외부 함수 outerFunc의 렉시컬 환경입니다. 그렇기 때문에 a변수를 참조할 수 있습니다.

 

즉, innerFunc 렉시컬 환경의 외부 렉시컬에 대한 참조에 outerFunc의 렉시컬 환경이 바인딩됩니다. 이렇게 렉시컬 스코프를 통해 참조 가능한 현상이 위 번역에서 '주변 상태 (렉시컬 환경)에 대한 참조와'에 해당되는 부분입니다.

내부 슬롯 [[Environment]]

함수가 정의된 환경과 호출되는 환경은 다를 수 있습니다. 따라서 함수는 자신이 호출되는 환경과 상관없이 자신이 정의된 환경, 즉 상위 스코프를 기억해야 합니다. 이때 함수는 [[Environment]] 내부 슬롯에 자신이 정의된 환경(현재 실행 중인 실행 컨텍스트의 환경)을 저장합니다. 이때 자신이 정의된 환경이 상위 스코프 환경이 되는 것입니다. 이 [[Environment]] 내부 슬롯에 참조된 환경이 함수가 호출되었을 때 생성되는 함수 렉시컬 환경의 외부 렉시컬 환경에 대한 참조'에 저장될 참조값입니다.

 

정리하면 함수는 [[Environment]] 내부 슬롯에 상위 스코프를 저장합니다.

 

위 예제에서는 innerFunc의 [[Environment]] 내부 슬롯에 outerFunc 함수의 렉시컬 환경 참조값이 저장됩니다.

클로저와 렉시컬 환경

const a = 1;

function outer() {
  const a = 2;
  const inner = function () {
    console.log(a);
  };
  
  return inner;
}

const innerFunc = outer();

innerFunc(); // 2

outer 함수를 호출하면 중첩함수 inner를 반환하고 생명 주기를 마감합니다. outer 함수의 실행 컨텍스트가 실행 컨텍스트 스택에서 팝된 것입니다. 그러나 inner의 [[Environment]] 내부 슬롯에 outer 함수의 렉시컬 환경이 참조되고 있기 때문에 outer 함수의 렉시컬 환경은 삭제되지 않습니다. 그렇기 때문에 외부 함수가 생명 주기를 마감했어도 중첩 함수가 호출할 때 외부 함수의 지역 변수에 접근할 수 있는데, 이러한 함수들의 조합을 클로저라 부릅니다.

클로저 활용

클로저는 상태를 안전하게 변경하고 유지하기 위해 사용합니다. 상태를 안전하게 은닉하고 특정함수에게만 상태 변경을 허용하기 위해 사용할 수 있습니다.