FrontEnd/JavaScript
Modern JavaScript 클로저
is..cy
2023. 1. 29. 13:26
1. 클로저란

- excution context 에서 필요한 개념으로, 함수 선언시 렉시컬 환경 (어디에 함수를 선언하였는가, 외부/내부)의 조합을 의미
- excution context 관점에서 innerFunc이 호출되면 context에 stack이 쌓이고 Variable Object와 Scope chain, this에 바인딩할 객체가 결정된다.
- outerFunc의 Activation Object, 함수자신을 순차적으로 바인딩하며 scope chain이 바인딩한 객체가 렉시컬 스코프 범주의 개념이다.
- 반환된 내부 함수가 자신이 선언되었을 때의 환경 (Lexical environment)인 스코프를 기억하여 자신이 선언되었을 때의 환경(스코프)밖에서 호출되어도 Lexical environment를 기억하는 함수 -> 스코프체인을 통해 참조
- 상태 변경이나 가변데이터를 피하고 불변성을 지향하는 함수형 프로그래밍으로 부수효과를 최대한 억제하여 오류를 피함 (안정성)
- 메모리 차원에서는 손해보는 환경
function outerFunc() {
var x = 10;
var innerFunc = function () { console.log(x); };
innerFunc();
}
outerFunc(); // 10
* innerFunc 함수가 변수x 검색 --> 실패 --> outerFunc (활성객체) 에서 변수 x (자유변수) 검색 --> 성공 --> 반환 (콜스택, 실행 컨택스트에서 outerFunc 소멸)
- 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되어도 외부함수의 지역 변수에 접근할 수 있다.
2. 클로저 활용
- 상태유지 : 현상태를 기억하고 변경된 상태 유지
- isShow (Lexical environment의 변수, 생성시 기억) : 클로저가 기억하는 변수
- 이벤트 핸들러인 클로저를 제거하지 않는한 isShow는 소멸하지 않는다. (현상태 기억)
- 버튼 클릭시 이벤트핸들러 클로저 호출
- isShow값 변경 및 최신상태 유지
<!DOCTYPE html>
<html>
<body>
<button class="toggle">toggle</button>
<div class="box" style="width: 100px; height: 100px; background: red;"></div>
<script>
var box = document.querySelector('.box');
var toggleBtn = document.querySelector('.toggle');
var toggle = (function () {
var isShow = false;
// ① 클로저를 반환
return function () {
box.style.display = isShow ? 'block' : 'none';
// ③ 상태 변경
isShow = !isShow;
};
})();
// ② 이벤트 프로퍼티에 클로저를 할당
toggleBtn.onclick = toggle;
</script>
</body>
</html>
- 전역 변수 사용 억제
- counter (전역변수) : 전역변수로 언제든 접근 및 변경 가능
- increase (클로저) : 의도치 않게 값이 변경 되는 것을 방지 (자신이 생성됐을 때의 환경을 기억)
<!DOCTYPE html>
<html>
<body>
<p>전역 변수를 사용한 Counting</p>
<button id="inclease">+</button>
<p id="count">0</p>
<script>
var incleaseBtn = document.getElementById('inclease');
var count = document.getElementById('count');
// 카운트 상태를 유지하기 위한 전역 변수
var counter = 0;
function increase() {
return ++counter;
}
incleaseBtn.onclick = function () {
count.innerHTML = increase();
};
</script>
</body>
</html>
- 정보의 은닉
- public property : counter가 this에 바인딩된 프로퍼티라면 Counter는 외부에서 접근 가능
- private 하게 사용 : 아래 예시는 Counter 내에서 선언된 변수 counter는 외부에서 접근 불가
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