정리/JavaScript

[JS] 클로저

루미미 2024. 11. 19. 22:41

렉시컬 스코프란?

JS 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정하는데 이를 렉시컬 스코프라 한다.

 

함수의 상위 스코프는 함수를 어디서 정의했느냐에 따라 결정되므로 함수를 어디서 호출하는지는 함수의 상위 스코프 결정에 어떠한 영향을 주지 못한다. 즉, 함수의 상위 스코프는 함수를 정의한 위치에 의해 정적으로 결정되고 변하지 않는다.

 

함수 객체의 내부 슬롯

렉시컬 스코프가 가능하려면 함수는 자신의 상위 스코프를 기억해야 한다. 이를 위해 함수는 자신의 내부 슬롯에 상위 스코프의 참조를 저장한다.

 

이때 자신의 내부 슬롯에 저장된 상위 스코프의 참조는 현재 실행 중인 실행 컨텍스트의 렉시컬 환경을 가리키는데 함수 객체를 생성하는 시점은 상위 함수가 실행되고 있는 시점이고 그 시점에 실행 중인 실행 컨텍스트는 상위 함수의 실행 컨텍스트이기 때문이다.

 

클로저란?

함수는 상위 함수의 실행 컨텍스트가 실행 컨텍스트 스택에서 사라져도 내부 슬롯에 저장된 상위 스코프에 의존하여 상위 스코프 내의 식별자를 참조할 수 있게 된다.

 

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

  return inner;
}

const innerFunc = outer();

innerFunc();

 

위 코드에서 outer 함수를 호출하면 outer 함수는 중첩 함수 inner를 반환하고 outer 함수의 실행이 종료되면 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 제거된다. 동시에 변수 x 또한 유효하지 않게 된다.

 

x 변수에 접근할 수 있는 방법이 없어 보이지만 실행 결과 콘솔에는 1이 나타난다.

 

이처럼 외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명 주기가 종료된 외부 함수의 변수를 참조할 수 있는데 이러한 중첩 함수를 클로저라고 부른다.

 

위 코드에서 outer 함수의 렉시컬 환경까지 소멸되지는 않는다. outer 함수의 렉시컬 환경을 inner 함수의 내부 슬롯에 의해 참조되고 있고 inner 함수는 전역 변수 innerFunc에 의해 참조되고 있으므로 가비지 컬렉션의 대상이 되지 않기 때문이다.

 

클로저의 장점

상태 유지

클로저는 함수 실행이 끝난 후에도 특정 변수의 상태를 유지할 수 있어서 값을 지속적으로 참조하거나 수정할 수 있다.

 

데이터 은닉

클로저를 사용하면 외부에서 접근할 수 없는 변수를 만들 수 있다. 이는 데이터 보호와 무분별한 접근 방지를 가능하게 해준다.

 

모듈화

클로저 함수를 각각의 변수에 할당하면 각자 독립적으로 값을 사용할 수 있고 데이터를 함께 묶어 모듈화를 구현할 수 있다. 이를 통해 코드의 구조가 더 깔끔하고 유지보수성이 향상된다.