\(@^0^@)/
[BOOK] 코어 자바스크립트, 클로저 1 본문
728x90
오늘 읽은 범위 : (클로저) p115 ~ p.124
< 책에서 기억하고 싶은 내용 >
클로저
클로저의 의미
- 자신을 내포하는 함수의 콘텍스트에 접근할 수 있는 함수
- 함수를 선언할 때 만들어지는 유효 범위가 사라진 후에도 호출할 수 있는 함수
- 로컬 변수를 참조하고 있는 함수 내의 함수
- 어떤 함수에서 선언한 변수를 참조하는 내부 함수에서만 발생하는 현상
클로저의 원리
- 일반적인 외부 함수의 변수를 참조하는 내부 함수
var outer = function () {
var a = 1;
var inner = function () {
console.log(++a);
};
inner();
};
outer();
- 클로저 발생하는 외부 함수의 변수를 참조하는 내부 함수
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
};
return inner;
};
var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
- 6번째 줄에서 inner 함수의 실행 결과가 아닌 inner 함수 자체를 반환했음.
- 스코프 체이닝에 따라 outer에서 선언한 변수 a에 접근해서 1만큼 증가시킨 후 그 값인 2를 반환하고, inner함수의 실행 콘텍스트가 종료된다.
- 10번째 줄에서 다시 outer2를 호출하면 같은 방식으로 a의 값을 2에서 3으로 1 증가시킨 후 3을 반환함.
- inner함수의 실행 시점에는 outer함수는 이미 실행이 종료된 상태인데 outer함수의 LexicalEnviornment에 접근할 수 있는 이유는 가비지 컬렉터(GC)의 동작 방식 때문.
- 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함시키지 않는다.
- 따라서, 외부 함수인 outer의 실행이 종료되더라도 내부 함수인 inner함수는 언젠가 outer2를 실행함으로써 호출될 가능성이 열린 것.
- 클로저 : 어떤 함수 A에서 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우 A의 실행 콘텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상.
- 주의할 점
- '외부로 전달'이 곧 return만을 의미하는 것은 아니다.
- return 없이도 클로저가 발생하는 다양한 경우 : setInterval/setTimeout/eventListener
// (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);
})();
// (2) eventListener
(function () {
var count = 0;
var button = document.vreateElement('button');
button.innerText = 'click';
button.addEventListener('click', function () {
console.log(++count, 'times clicked');
});
document.body.appendChild(button);
})();
클로저와 메모리 관리
- 메모리 누수의 위험을 이유로 클로저 사용을 조심해야 한다거나 지양해야 한다고 주장하는 사람들도 많지만,
메모리 소모는 클로저의 본질적인 특성일 뿐임. 이러한 특성을 정확히 이해하고 잘 활용하도록 노력해야 함. - 개발자가 의도적으로 참조 카운트를 0이 되지 않게 설계한 경우는 '누수'라고 할 수 없다.
의도대로 설계한 '메모리 소모'에 대한 관리법만 잘 파악해서 적용하는 것으로 충분 - 관리 방법
- 클로저는 어떤 필요에 의해 의도적으로 함수의 지역변수 메모리를 소모하도록 함으로써 발생한다.
그렇다면 그 필요성이 사라진 시점에 더는 메모리를 소모하지 않게 해 주면 되는 것. - 참조 카운트를 0으로 만들면 언젠가 GC가 수거해갈 것이고, 이때 소모됐던 메모리가 회수된다.
- 참조 카운트를 0으로 만드는 방법 : 식별자에 참조형이 아닌 기본형 데이터(보통 null이나 undefined)를 할당.
- 클로저는 어떤 필요에 의해 의도적으로 함수의 지역변수 메모리를 소모하도록 함으로써 발생한다.
// (1) return에 의한 클로저의 메모리 해제
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
};
return inner;
};
console.log(outer());
console.log(outer());
outer = null; // outer 식별자의 inner 함수 참조를 끊음.
// (2) setInterval에 의한 클로저의 메모리 해제
(function () {
var a = 0;
var intervalId = null;
var inner = function () {
if (++a >= 10) {
clearInterval (intervalId);
inner = null; // inner 식별자의 함수 참조를 끊음
}
console.log(a);
};
intervalId = setInterval(inner, 1000);
})();
// (2) eventListener에 의한 클로저의 메모리 해제
(function () {
var count = 0;
var button = document.vreateElement('button');
button.innerText = 'click';
var clickHandler = function () {
console.log(++count, 'times clicked');
if (count >= 10) {
button.removeEventListener('click', clickHandler);
clickHandler = null; // clickHandler 식별자의 함수 참조를 끊음
}
};
< 정리 >
- 클로저란 어떤 함수 A에서 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우 A의 실행 콘텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상.
- 메모리 소모는 클로저의 본질적인 특성일 뿐임. 이러한 특성을 정확히 이해하고 잘 활용하도록 노력해야 함.
- 참조 카운트를 0으로 만들면 언젠가 GC가 수거해갈 것이고, 이때 소모됐던 메모리가 회수된다.
- 참조 카운트를 0으로 만드는 방법 : 식별자에 참조형이 아닌 기본형 데이터(보통 null이나 undefined)를 할당.
[ 출처 : 코어 자바스크립트 ]
[ 참고 : https://www.youtube.com/watch?v=tpl2oXQkGZs&list=PLZKTXPmaJk8JZ2NAC538UzhY_UNqMdZB4&index=11 ]
[ 참고 : https://www.youtube.com/watch?v=Um-CJHNc5Pw ]
728x90
'BOOKS > 코어 자바스크립트' 카테고리의 다른 글
[BOOK] 코어 자바스크립트, 프로토타입 1 (0) | 2022.04.07 |
---|---|
[BOOK] 코어 자바스크립트, 클로저 2 (0) | 2022.04.04 |
[BOOK] 코어 자바스크립트, 콜백 함수 (0) | 2022.03.18 |
[BOOK] 코어 자바스크립트, this(2) (0) | 2022.03.14 |
[BOOK] 코어 자바스크립트, this(1) (0) | 2022.03.11 |