볼 때마다 헷갈리는 Closure 정복하기

wkawhaRo·2024년 3월 9일

Closure란?

클로저는 주변 상태(어휘적 환경)에 대한 참조와 함께 묶인(포함된) 함수의 조합입니다. 즉, 클로저는 내부 함수에서 외부 함수의 범위에 대한 접근을 제공합니다. JavaScript에서 클로저는 함수 생성 시 함수가 생성될 때마다 생성됩니다.

MDN 공식문서에 나온 정의는 위와 같다.

  • 주변 상태(어휘적 환경)에 대한 참조
  • 함께 묶인 함수

의 조합이라고 하는데 말이 너무 어려워서 예시 코드를 보며 이해해 보았다.

예제 1

function init() {
  var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
  function displayName() {
    // displayName() 은 내부 함수이며, 클로저다.
    console.log(name); // 부모 함수에서 선언된 변수를 사용한다.
  }
  displayName();
}
init();

일단 위 정의에서 나온 ‘클로저는 내부 함수에서 외부 함수의 범위에 대한 접근을 제공’하는 부분을 통해 displayName 이 클로저임을 알 수 있다.

why?

⇒ init 함수의 내부 함수이며, displayName 함수는 본인 외부에 있는 변수 name 을 참조하고 있기 때문이다.

그런데 저 예제의 흐름을 보면

  1. init 함수를 실행
  2. 내부에서 displayName 함수를 실행
  3. console.log 로 name 을 찍기 때문에 사실 클로저라고 보기 어렵다.

예제2

다음 코드를 보자.

function init() {
  var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
  function displayName() {
    // displayName() 은 내부 함수이며, 클로저다.
    console.log(name); // 부모 함수에서 선언된 변수를 사용한다.
  }
  return displayName();
}
const test = init();
test();

자, 위 예제에 대한 흐름을 보자

  1. test 에 init 함수 호출하며 할당
  2. init 은 displayName 함수를 반환하면서 종료됨
  3. test 는 displayName 함수를 가지게 됨
  4. test 를 실행하여 displayName 함수를 실행
  5. 이 때, init 함수는 종료되면서 지역변수인 name 은 존재하지 않는다
  6. 하지만 closure인 displayName 는 생성될 당시의 name 을 참조하게 된다.
  7. 고로 콘솔창에는 “Mozilla” 값이 나오게 된다!!

즉 displayName 이 생성되는 시점(9번째 라인)에서 init 의 name 을 참조한다. 이것이 함수 생성 시 주변 환경(어휘적 환경)을 참조하는 것이다.

정리

💡 Closure는 함수가 선언될 때의 환경을 기억하여 이 함수가 다른 스코프에서 호출될 때에도 기억했던 환경(변수 등)에 접근할 수 있게 하는 JavaScript의 특징이다
profile
1일 1백준을 목표로

0개의 댓글