클로저

클로저(Closure)

클로저는 자바스크립트 고유의 개념이 아니라 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에 사용되는 특성이다.

클로저는 함수와 그 함수가 선언됐을 때의 어휘적 환경과의 조합이다.

위 문장에서 두 단어의 의미가 모호하다. 함수어휘적 환경이다.

어휘적 환경이란 이 함수가 선언됐을 때의 스코프이다.

함수란, 이 스코프에서 반환된 내부함수를 의미한다.

즉, 위 문장을 다시 풀어서 쓰면

클로저는 반환된 내부함수와 그 내부함수가 선언됐을 때의 스코프와의 조합이다.

function outerFunc() {
  var x = 10;
  var innerFunc = function () {
    console.log(x);
  };
  innerFunc();
}

outerFunc(); // 10

outerFunc 에서 내부함수 innerFunc가 선언되었고, 호출됐다. innerFunc는 자신을 감싸고있는 외부함수 outerFunc의 변수인 x에 접근할 수 있는데, 이는 innerFuncouterFunc의 내부에서 선언됐기 때문이다.

이 때, 내부함수 innerFunc의 상위 스코프는 outerFunc이다. outerFunc의 상위 스코프는 전역 스코프이다.

즉, 스코프는 함수가 호출되는 위치가 아니라, 어디에 선언했는지에 따라 결정되는데, 이를 렉시컬 스코핑(Lexical Scoping) 이라 한다.

innerFuncouterFunc의 내부함수이므로, 자신이 속한 렉시컬 스코프를 참조할 수 있다.

innerFunc의 렉시컬 스코프는 자신인 innerFunc, 자신의 외부함수인 outerFunc 그리고 전역이 된다.

innerFunc는 자신의 렉시컬 스코프를 참조할 수 있다.

그 이유는 렉시컬 스코프를 참조하기 위해 실행 컨텍스트에 저장된 스코프 체인을 자바스크립트 엔진이 검색했기 때문이다.

innerFunc가 호출되면 자신의 실행 컨텍스트가 실행 컨텍스트 스택에 쌓인다. 그리고 변수 객체, 스코프 체인과 this에 바인딩할 객체가 결정된다.

이 때의 스코프 체인은 전역 스코프를 가리키는 전역 객체, outerFunc의 스코프를 가리키는 outerFunc 함수의 활성 객체(Activation object), 그리고 innerFunc 자신의 스코프를 가리키는 활성 객체를 순서대로 바인딩한다.

스코프 체인이 바인딩한 객체가 렉시컬 스코프의 실체가 된다.

그렇기 때문에, innerFunc의 스코프(함수 자신의 활성 객체) 내에서 변수 x를 탐색했을 때 탐색에 실패하고, innerFunc의 외부함수 outerFunc의 스코프(outerFunc 자신의 활성 객체)에서 변수 x를 탐색한다. 변수 x를 찾을 수 있게 된다.

즉, innerFunc가 자신을 감싸고있는 외부함수 outerFunc의 변수 x에 접근할 수 있는 것이다.

만약, 외부함수가 내부함수를 반환하고 이후 더이상 호출되지 않고, 내부함수만 호출한다면 innerFunc의 외부에 선언된 변수 x를 참조할 수 있을까?

가능하다.

내부함수가 호출될 때, 내부함수 자신의 스코프를 가리키는 활성 객체 내부에서 변수 x 를 찾고, 없다면 외부함수 스코프에서 변수 x 를 탐색하기 때문이다.

이처럼 자신을 포함하는 외부함수의 밖에서 자신(내부함수)가 호출이 되더라도 외부함수의 지역 변수에 접근할 수 있는 함수를 클로저(Closure) 라고 부른다.

내부함수가 선언됐을 때의 환경(Lexical Environment) 스코프를 기억하고, 이후 그 환경의 밖에서 호출되어도 그 환경에 접근할 수 있는 함수인 것이다.

한 문장으로 요약하면,

클로저는 자신이 생성될 때의 환경을 기억하는 함수이다.

Reference

YUNSU BAE

YUNSU BAE

주니어 웹 개발자 배윤수 입니다!

예술의 영역을 동경하고 있어요. 🧑‍🎨