클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경과의 조합이다. 즉 외부 변수를 기억하고 이 외부 변수에 접근할 수 있는 함수를 의미한다.
환경 레코드
외부 렉시컬 환경
function outer() {
var x = 10;
var inner = function () {
console.log(x); };
inner();
}
outer(); //10
함수 outer 내에서 내부함수 inner가 선언되고 호출되었다. 이때 내부함수 inner는 자신을 포함하고 있는 외부함수 outer의 변수 x에 접근할 수 있다. 이는 함수 inner가 함수 outer 내부에 선언되었기 때문이다.
스코프는 함수를 호출할 때가 아니라 함수를 어디에 선언하였는지에 따라 결정된다.
이를 렉시컬 스코핑이라고 한다.
함수 inner가 함수 outer의 내부에 선언된 내부함수이므로 함수 inner는 자신이 속한 렉시컬 스코프(전역, 함수 Outer, 자신의 스코프)를 참조할 수 있다.
function outer() {
var x = 10;
var inner = function() {
console.log(x);
};
return inner;
}
var inner = outer();
inner(); // 10
함수 outer는 내부함수 inner를 반환하였다. 즉 함수 outer는 실행된 이후 call stack에서 제거되었으므로 함수 outer의 변수 x 또한 더 이상 유효하지 않게 되어 변수 x에 접근할 수 있는 방법이 없어보인다 하지만 위 코드의 실행 결과 변수 x는 값 10이 출력이 된다. 이미 life-cycle이 종료되어 call stack에서 제거된 함수 outer의 지역변수 x가 다시 살아나서 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되더라고 외부함수의 지역 변수에 접근할 수 있는 이러한 함수를 클로저라고 한다.
function makeCounter() {
let count = 0;
return function() {
return count++
};
}
let counter = makeCounter();
makeCounter()
를 호출하면 호출할 때마다 새로운 렉시컬 환경 객체가 만들어진다.makeCounter
를 실행하는데 필요한 변수들이 저장된다.