클로저란 무엇이고, 원리와 왜 사용하나요?
개념적으로 자바스크립트의 모든 함수는 클로저이지만, 실제로 우리는 자바스크립트의 모든 함수를 전부 클로저라고 부르지는 않는다.
클로저란 어떤 함수 A에서 선언한 변수 c를 참조하는 내부함수 B를 외부로 전달할 경우, A의 실행 컨텍스트가 종료된 이후에도 변수 c가 사라지지 않는 현상이 나타나는데, 이 때 B와 같은 함수를 클로저라고 부른다.
해당 함수와 그 함수의 외부를 둘러싸고 있는 렉시컬 환경의 조합이다. 다른 말로하면, 클로저란 내부 함수에서 외부 함수 스코프에 접근할수 있는 권한으로, 함수를 만들고 그 함수 내부의 코드가 탐색하는 스코프를 함수 생성 당시의 렉시컬 스코프로 고정하면 바로 클로저가 되는 것이다
예시)
중요한 부분은 2~4번, 그리고 7번이다. bar는 자신이 생성된 렉시컬 스코프에서 벗어나 global에서 baz라는 이름으로 호출이 되었고, 스코프 탐색은 현재 실행 스택과 관련 없는 foo를 거쳐 갔다. baz를 bar로 초기화할 때는 이미 bar의 outer lexical environment를 foo로 결정한 이후이다. 때문에, bar의 생성과 직접적인 관련이 없는 global에서 아무리 호출하더라도 여전히 foo에서 color를 찾는 것이다. 이런 bar(또는 baz)와 같은 함수를 우리는 클로저라고 부른다.
자바스크립트 엔진의 가비지 컬렉터의 동작 방식 때문이다. 가비지 컬렉터는 쓸모없는 메모리 처리를 끊임없이 수행한다. 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함하지 않는다.
ex) 즉시호출함수 A에서 선언한 변수 c를 내부함수 B가 참조하고 있으면, c는 A의 실행컨텍스트가 종료되었다 하더라도 가비지 컬렉터의 대상이 되지 않음.
// 이 객체의 프로퍼티가 또 다른 객체를 참조하고 있다면, 프로퍼티가 참조하는 객체는 도달 가능한 값으로 보고, 가비지 컬렉터의 대상에 포함시키지 않는다.
즉시실행함수의 자유변수(클로저에 의해 참조되는 외부함수의 변수)와 반환을 이용한 클로저를 활용하면
1) 현재 상태를 기억하고 변경된 최신 상태를 유지
2) 전역 변수의 사용 억제
3) 정보의 은닉
등에 활용할 수 있다. 이를 통해 보다 안정적인 프로그래밍이 가능해진다.
var toggle = (function () {
var isShow = false;
// ① 클로저를 반환
return function () {
box.style.display = isShow ? 'block' : 'none';
// ③ 상태 변경
isShow = !isShow;
};
})();
// ② 이벤트 프로퍼티에 클로저를 할당
toggleBtn.onclick = toggle;
var increase = (function () {
// 카운트 상태를 유지하기 위한 자유 변수
var counter = 0;
// 클로저를 반환
return function () {
return ++counter;
};
}());
incleaseBtn.onclick = function () {
count.innerHTML = increase();
};
function Counter() {
// 카운트를 유지하기 위한 자유 변수
var counter = 0;
// 클로저
this.increase = function () {
return ++counter;
};
// 클로저
this.decrease = function () {
return --counter;
};
}
const counter = new Counter();
console.log(counter.increase()); // 1
console.log(counter.decrease()); // 0
const a = 1; // 전역 스코프
console.log(a); //1
{
const a = 2; // 블럭 1 스코프
console.log(a);//2
{
const a = 3; // 블럭 2 스코프
console.log(a);//3
}
}
메모리 절약 뿐만 아니라, 성능을 위해서라도 변수는 최대한 필요한 곳에 정의 하는 것이 필요하다. 왜냐하면 해당 블럭에 없을 경우 스코프 체인을 통해 온 스코프를 다 돌아다녀야 하기 때문입니다.
참고
https://poiemaweb.com/js-closure
https://meetup.toast.com/posts/86
https://hyunseob.github.io/2016/08/30/javascript-closure/
https://velog.io/@graphicnovel/JS-클로저의-의미와-원리-이해-Closure
https://codingsalon.tistory.com/24