어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상
var outer = function () {
var a = 1;
var inner = function () {
console.log(++a);
}
inner();
};
outer();
위의 코드는 다음의 실행 컨텍스트를 이용한다.
![[images_soheey_post_5279dcd3-1328-4215-88dd-25e4942f1d99_1번.jpg]]
일반적인 함수의 동작처럼 내부의 함수가 종료되고 그 다음에 외부의 함수가 종료되는 것을 볼 수 있다.
이때 외부 함수가 종료된 후에도 내부 함수를 호출할 수 있게 만들어 보자.
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
}
return inner;
};
var outer2 = outer();
console.log(outer2());
console.log(outer2());
console.log(outer2());
outer2에 저장된 함수 outer는 inner를 반환하게 되고 inner는 outer의 environmentRecord안에 a를 찍을 수 있는 outerEnvironmentReference를 갖고 있어서 내부적으로 outer의 environmentRecord에 접근해서 a를 더하고 그걸 리턴한다.
여기서 outer는 이미 실행 컨텍스트가 끝났지만 inner가 outer의 environmentRecord를 바꾸는 모습을 볼 수 있다.
그 이유는 garbage collector 동작 방식 때문이다.
어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함시키지 않는다.
![[Pasted image 20240401081421.png]]
(spec에서는 lexical environment 전부를 gc하지 않는걸로 되어 있지만 nodejs환경에서는 environmentRecord만 남기는 걸로 최적화 되어 있다.)
이처럼 lexical environment(위의 environmentRecord)가 실행 컨텍스트 종료 이후에도 존재하는 건(GC가 처리하지 않고) 내부 함수 자체가 외부로 전달된 경우가 유일하다.
즉 Closer는 함수가 종료된 후에도 그 함수의 내부 함수에서 여전히 바깥 함수의 변수를 사용하여 그 변수가 사라지지 않는 현상을 뜻한다. (closed된 funciton의 변수를 여전히 사용)
// 1. setInterval / setTimeout
(function(){
var a= 0;
var intervalId = null;
var inner = function(){
if (++a>=10){
clearInterval(intervalId);
}
console.log(a);
};
intervalId=setInterval(inner,1000);
// window 라는 외부 객체의 메서드(setInterval)의 콜백함수가
// 바깥 함수의 변수 a를 외부로 전달한다.
})();