[JavaScript] 클로저 Closure

정의

클로저란 ?

클로저는 자바스크립트 고유의 개념이 아니다. 함수를 일급객체로 취급하는 함수형 프로그래밍 언어에서 공통적으로 사용되는 특성이다. 따라서 ECMAScript 사양에 정의되어있지 않다. 대신 MDN에 따른 클로저의 정의는 다음과 같다.

클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.

렉시컬 환경? 렉시컬 환경과의 조합? 처음 읽을 때는 무슨 말인지 도통 이해가 가질 않는다. 정의를 이해하기 위해 먼저 아래 코드들을 살펴보자

// 1. inner 함수가 outer 함수 바깥에서 정의된 경우
const x = 1;

function outer() {
	const x = 10;
  	inner();
}

function inner() {
	console.log(x);
}

outer(); // 1

// 2. inner 함수가 outer 함수 내부에서 정의된 경우
const x = 1;

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

    inner();
}

outer(); // 10

코드를 실행해보면, inner 함수가 정의된 위치에 따라 참조하는 변수 x 가 달라지는 것을 확인할 수 있다. outer 함수 외부에서 inner 함수를 선언했을 때는 outer 외부의 변수 x 를 참조하고, outer 함수 내부에서 inner 함수를 선언했을 때는 outer 내부의 변수 x 를 참조한다.

자바스크립트는 정적 스코프를 따르는 언어이다. (대부분의 언어가 그렇다) 정적 스코프를 따르는 언어는 함수가 선언된 위치에 따라 상위 스코프가 정해진다. 즉 어디에 함수를 정의했는지에 따라서 상위 스코프가 정해진다.

또한 자바스크립트에서 스코프라는 개념은 렉시컬 환경 을 통해 구현된다. 즉 렉시컬 환경 이 스코프의 실체라고 할 수 있다.

쉽게 보는 정의

MDN에 의한 클로저의 정의를 다시 한번 보자

클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.

위에서 말했듯이 정적 스코프를 따르는 언어는 함수가 선언된 위치에 따라 상위 스코프(상위 렉시컬 환경)가 정해진다. 따라서 정의를 쉽게 바꾸면 다음과 같다.

클로저는 함수와 그 함수의 상위 스코프와의 조합이다.

그래서 함수와 그 함수의 상위 스코프를 어떻게 조합할 수 있을까?

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

const inner = outer(); // ...(*)
inner(); // 10

위 코드는 outer 함수 외부와 내부에 각각 다른 값을 가지는 변수 x를 선언하고, 중첩함수 inner 로 하여금 console.log 를 통해 x 를 출력하게 만든다. (*) 에서 outer 함수의 호출 후 outer 함수의 실행이 끝나면 outer 함수의 생명주기도 종료되어 outer 함수 내부 변수 x 에 접근할 수 없을 것 처럼 보인다.