Closure (클로저) 너 뭐니?🤷🏻‍♂️

Seob·2020년 11월 7일
0

TIL

목록 보기
36/36
post-thumbnail

💡 [코어자바스크립트-정재남, 위키북스]를 참고&인용하여 블로그를 작성했습니다.

클로저는 여러 함수형 프로그래밍 언어에서 등장하는 보편적인 특성이다. 자바스크립트만의 고유한 개념이 아니라 ECMAScript 명세에서도 클로저를 따로 정의하지 않는다.

Closure의 사전적 정의

다양한 서적에서 클로저를 한 문장으로 요약📚

  • 자신을 내포하는 함수의 컨텍스트에 접근할 수 있는 함수 - 더글라스 크록포트, <자바스크립트 핵심 가이드>, 한빛미디어
  • 함수가 특정 스코프에 접근할 수 있도록 의도적으로 그 스코프에서 정의하는 것 - 에든 브라운, <러닝 자바스크립트>, 한빛미디어
  • 함수를 선언할 때 만들어지는 유효범위가 사라진 후에도 호출할 수 있는 함수 - 존 레식, <자바스크립트 닌자 비급>, 인사이트
  • 이미 생명 주기상 끝난 외부 함수의 변수를 참조하는 함수 - 송형주 고현준, <인사이트 자바스크립트>, 한빛미디어
  • 자유변수가 있는 함수와 자유변수를 알 수 있는 환경의 결합 - 에릭 프리먼, < Head First Javascript Programming>, 한빛미디어
  • 로컬 변수를 참조하고 있는 함수 내의 함수 - 야마다 요시히로, <자바스크립트 마스터북>, 제이펍
  • 자신이 생성될 때의 스코프에서 알 수 있었던 변수들 중 언젠가 자신이 실행될 때 사용할 변수들만을 기억하여 유지시키는 함수 - 유인동, <함수형 자바스크립트 프로그래밍>, 인사이트

MDN슨상님의 설명

MDN에서는 클로저에 대해 다음과 같이 설명한다.

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

클로저는 함수와 함수가 선언된 당시의 lexical environment의 조합이다. 즉, 클로저는 내부 함수가 외부 함수의 스코프에 접근할 수 있게 해주는 것을 의미한다. 자바스크립트에서 함수가 생성될 때마다 함수가 생성된 시점에 클로저가 함께 생성된다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.

일단 눈으로 보고 이해해보기 👀

function outer(x) {
  return function inner() {
    return x;
  }
}

const two = outer(2);
console.log(two()) // 2

outer 함수 안에는 inner함수가 있다. inner함수는 outer 함수에 인자로 들어간 x를 리턴한다.

outer 함수가 호출되면 outer의 생명주기는 끝난다. 하지만, inner 함수는 x를 참조한다.

위의 코드 예시처럼 외부 스코프를 기억하고 있는 것을 Closure(클로저) 라고 한다.

다 이해하지 못해도 괜찮은 조-금 어려운 버전 💆🏻‍♂️

const outer = () => {
  let a = 0;
  const inner = () => {
    console.log(a += 1)
  };
  inner();
};
outer(); // 1

outer함수 안에서 변수 a를 선언했고, outer함수 내부에 inner함수에서 a의 값을 1 증가시킨 후 출력했다. inner함수 내부에서 a를 선언하지 않았기 때문에 environmentRecord에서 값을 찾지 못하므로 outerEnvironmentReference에 지정된 상위 컨텍스트인 outerLexicalEnvironment에 접근해서 다시 a를 찾는다. outer 함수의 실행 컨텍스트가 종료되면 LexicalEnvironment에 저장된 식별자들(a, inner)에 대한 참조를 지운다. 그러면 각 주소에 저장돼 있던 값들은 자신을 참조하는 변수가 하나도 없게 되므로 가비지 컬렉터의 수집 대상이 될 것이다.

위의 내용을 조금 바꿔서 다른 예시를 살펴보자

const outer = () => {
  let a = 0;
  const inner = () => {
    return a += 1
  };
  return inner();
};
const outer2 = outer();
console.log(outer2); // 1

이번에도 inner 함수 내부에서 외부변수인 a를 사용했다. 하지만 6번째 줄에서 inner 함수를 실행한 결과를 리턴하고 있으므로 결과적으로 outer 함수의 실행 컨텍스트가 종료된 시점에서는 a 변수를 참조하는 대상이 없어진다. 이 전의 예시와 마찬가지로 a, inner 변수의 값들은 가비지 컬렉터의 수집 대상이 될 것이다. 역시 일반적인 함수 및 내부함수에서의 동작과 차이가 없다.

마무리

클로저란 어떤 함수에서 선언한 변수를 참조하는 내부함수를 외부로 전달할 경우 함수의 실행 컨텍스트가 종료된 후에도 해당 변수가 사라지지 않는 현상이다.

  • 내부함수를 외부로 전달하는 방법에는 함수를 return하는 경우 뿐 아니라 콜백으로 전달하는 경우도 포함된다.
  • 클로저는 그 본질이 메모리를 계속 차지하는 개념이므로 더는 사용하지 않게 된 클로저에 대해서 메모리를 차지하지 않도록 관리해줄 필요가 있다.
profile
Hello, world!

0개의 댓글