[JavaScript] 클로저의 개념 (실행 컨텍스트, 렉시컬 환경을 곁들인)

problem_hun·2022년 12월 26일
0

TIL

목록 보기
4/10

“A closure is the combination of a function and the lexical environment within which that function was declared.”

클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.

- MDN

말이 무척이나 난해하니 우선 렉시컬 환경부터 알아보자.

렉시컬 환경


각각의 블록은 렉시컬 환경 이라는 블록 내부에 어떤 데이터가 있는지, 외부 환경은 어떤지 내장 객체를 가지고 있다.

  • 환경 레코드 : 현재 블록에 해당하는 데이터
  • 외부 환경 참조 : 외부 환경(부모 블록)에 대한 데이터

예를 들어 블럭2의 렉시컬 환경은 환경레코드(변수 a = 3;)와 외부 환경 참조(변수 a = 2;)를 가지고 있다. 그렇다면 다음 예제를 살펴보자.

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

outerFunc(); // 10

함수 outerFunc 내에서 내부함수 innerFunc가 선언되고 호출되었다. 이때 내부함수 innerFunc는 자신을 포함하고 있는 외부함수 outerFunc의 변수 x에 접근할 수 있다. 이는 함수 innerFunc가 함수 outerFunc의 내부에 선언되었기 때문에 innerFunc의 렉시컬 환경의 외부환경 참조로 가능해진다.


이번에는 실행 컨텍스트를 알고 난 뒤에,
내부함수 innerFunc를 함수 outerFunc 내에서 호출하는 것이 아니라 반환하도록 변경해 보자.

실행 컨텍스트 스택


자바스크립트 런타임 환경에는 콜스택(=컨텍스트 스택)이 있으며, 콜스택을 통해 함수 실행순서를 기억한다. 자바스크립트에서는 하나의 컨텍스트 스택이 있어 한 번에 하나의 일만 수행할 수 있다.

쉽게 말해, 자바스크립트 파일을 읽으면서 함수를 위에서 아래로 순서대로 실행하는데 한번에 하나의 함수만 실행시킬 수 있다. 실행이 끝난 함수는 콜스택에서 사라지게 되며, 접근이 더 이상 불가능해진다.

이제 클로져 예제를 살펴보자.

클로저

클로저 예제

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

/**
 *  함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
 *  그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
 */
var inner = outerFunc();
inner(); // 10

함수 outerFunc는 내부함수 innerFunc를 반환하고 생을 마감했다. 즉, 함수 outerFunc는 실행된 이후 콜스택(실행 컨텍스트 스택)에서 제거되었으므로 함수 outerFunc의 변수 x 또한 더이상 유효하지 않게 되어 변수 x에 접근할 수 있는 방법은 달리 없어 보인다.

그러나 위 코드의 실행 결과는 변수 x의 값인 10이다. 이미 life-cycle이 종료되어 실행 컨텍스트 스택에서 제거된 함수 outerFunc의 지역변수 x가 다시 부활이라도 한 듯이 동작하고 있다. 뭔가 특별한 일이 일어나고 있는 것 같다.

클로저 정의

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

다시 MDN의 정의로 돌아가 보자.

“A closure is the combination of a function and the lexical environment within which that function was declared.”

클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.

- MDN

위 정의에서 말하는 “함수”란 반환된 내부함수를 의미하고 “그 함수가 선언될 때의 렉시컬 환경(Lexical environment)”란 내부 함수가 선언됐을 때의 스코프를 의미한다. 즉, 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다. 이를 조금 더 간단히 말하면 클로저는 자신이 생성될 때의 렉시컬 환경(Lexical environment)을 기억하는 함수다라고 말할 수 있겠다.

+) 클로저에 의해 참조되는 외부함수의 변수 즉 outerFunc 함수의 변수 x를 자유변수(Free variable)라고 부른다. 클로저라는 이름은 자유변수에 함수가 닫혀있다(closed)라는 의미로 의역하면 자유변수에 엮여있는 함수라는 뜻이다.

profile
문제아

0개의 댓글