기술면접을 준비하는 과정에서 자바스크립트의 클로저 개념에 대해 공부하였고 클로저 개념에 대해 정리한다. 이 정리글은 코어 자바스크립트(정재남)를 참고하여 작성하였다.
처음에 클로저 개념을 공부하면서 무슨 말인지 감을 잡을 수 없었는데, 아래의 클로저 설명을 보고 클로저에 대한 느낌을 얻을 수 있었다. 클로저의 정확한 정의는 아니고, 클로저를 좀 더 이해하기 쉽게 하기 위해 고쳐서 설명한 정의이다.
클로저는 어떤 함수에서 선언한 변수를 참조하는 내부함수를 외부로 전달하는 경우 함수의 실행 컨텍스트가 종료된 이후에도 해당 변수가 사라지지 않는 현상을 말한다.
클로저는 '어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상'이다. 아래 예시들을 통해 클로저가 무엇인지 감을 잡을 수 있었다. 외부함수에서 변수를 선언하고, 내부함수에서 해당 변수를 참조하는 형태의 예시들이다.
var outer = function () {
var a = 1;
var inner = function () {
console.log(++a);
};
inner();
};
outer(); // 2
outer 함수에서 변수 a를 선언하고, outer 함수의 내부함수인 inner 함수에서 변수 a의 값을 1만큼 증가시킨 후 출력하고 있다.
outer 함수가 종료되면(outer 함수 실행 컨텍스트가 콜스택에서 사라짐) LexicalEnvironment에 저장된 식별자에 대한 참조가 삭제된다.
결국 outer 함수 실행 컨텍스트가 사라지면 LexicalEnvironment에 저장된 식별자 정보들도 사라지기 때문에 변수 a에 저장된 값들도 가비지 컬렉팅되어 사라진다. 클로저의 정의에 부합하지 않는다.
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
};
return inner();
};
var outer2 = outer();
console.log(outer2); // 2
inner 함수 내부에서 외부변수 a를 참조한다. outer 함수는 inner 함수 실행 결과를 리턴하므로 결과적으로 outer 함수가 종료되면(outer 함수 실행 컨텍스트가 콜스택에서 사라짐) 변수 a를 참조하는 대상이 사라진다.
예시 1과 마찬가지로 a, inner 변수의 값들은 가비지 컬렉팅되어 사라진다. 클로저의 정의에 부합하지 않는다.
위 예제들과 달리 outer 함수 종료 후에도 inner 함수를 호출할 수 있게 외부로 전달한다면 어떻게 될까.
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
};
return inner;
};
var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
outer 함수는 inner 함수 자체를 반환하고 있다.
inner 함수에는 어떤 변수도 존재하지 않으므로 inner 함수 실행 컨텍스트의 environmentRecord에 담길 식별자 정보가 없다. 그리고 inner 함수 실행 컨텍스트의 outerEnvironmentReference에는 inner 함수가 선언된 위치의 LexicalEnvironment가 참조복사된다.
예시 3은 클로저가 발생한다. 그 이유에 대해 알아보자.
inner 함수 실행 시점에 outer 함수는 이미 실행이 종료된 상태이다. 그런데 inner 함수 실행 컨텍스트의 outerEnvironmentReference는 outer 함수의 LexicalEnvironment에 접근하고 있다. 이것은 가비지 컬렉터의 동작 방식 때문에 가능하다.
함수의 실행 컨텍스트가 종료된 이후에도 LexicalEnvironment가 가비지 컬렉터의 수집 대상에서 제외되는 경우는 지역변수를 참조하는 내부함수가 외부로 전달된 경우뿐이다.
클로저 설명에서 언급한 '어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상'은 '외부 함수의 LexicalEnvironment가 가비지 컬렉팅되지 않는 현상'을 말하는 것이다.
다음과 같은 절차에 따라 클로저가 발생한다고 정리하였다.