<aside> 💬 클로저란 자신이 선언 되었을 때의 환경을 기억하고 있는 내부함수를 의미합니다.
</aside>
클로저를 사용하면 외부 함수 스코프에서 내부함수 스코프로 접근이 불가능하고 내부함수에서는 외부함수 스코프에서 선언된 변수에 접근이 가능하다. 따라서 내부 함수는 외부 함수에 선언된 변수에 접근이 가능하다. 이런 기능을 통해서 변수의 접근 범위를 닫을 수 있다.
<body>
<button class="toggle">button</button>
<div class="box"></div>
<script>
const box = document.querySelector(".box");
const toggleBtn = document.querySelector(".toggle");
const toggle = (function () {
let isShow = false;
return function () {
box.style.display = isShow ? "block" : "none";
isShow = !isShow;
};
})();
toggleBtn.onclick = toggle;
</script>
</body>
클로저가 가장 유용하게 사용되는 상황은 현재 상태를 기억하고 변경된 최신 상태를 유지할 수 있다. toggle버튼을 만들어 클로저로 관리한다고 가정해보자. toggle 버튼의 이벤트 프로퍼티에 클로저를 할당해서 이벤트를 발생시킬 경우 클로저가 제거되지 않는 한 최신상태가 변경되지 않는다.
<body>
<button class="inclease">+</button>
<p class="count">0</p>
<script>
const incleaseBtn = document.querySelector(".inclease");
const count = document.querySelector(".count");
let counter = 0;
function increase() {
return ++counter;
}
incleaseBtn.addEventListener("click", () => {
count.innerHTML = increase();
});
</script>
</body>
해당 예시를 통해 click이벤트가 발생하면 전역 변수인 couter의 값이 변경되는 부수효과가 발생한다. 이처럼 변수의 값은 누군가에 의해 언제든지 변경될 수 있어 오류 발생의 근본적 원인이 될 수 있다. 상태 변경이나 가변 데이터를 피하고 불변을 지향 ****하는 함수형 프로그래밍에서 부수 효과를 최대한 억제 ****하여 오류를 피하고 프로그램의 안정성을 높이기 위해 클로저는 적극적으로 사용된다.
<body>
<button id="inclease">+</button>
<p id="count">0</p>
<script>
const incleaseBtn = document.getElementById("inclease");
const count = document.getElementById("count");
const increase = (function () {
let counter = 0;
return function () {
return ++counter;
};
})();
incleaseBtn.addEventListener("click", () => {
count.innerHTML = increase();
});
</script>
</body>
클로저를 사용할 경우 전역 변수를 사용하지 않고선 변경된 이전 상태를 기억한다.
<body>
<button class="increase_btn">increase</button>
<button class="decrease_btn">decrease</button>
<p class="number">0</p>
<script>
const increaseBtn = document.querySelector(".increase_btn");
const decreaseBtn = document.querySelector(".decrease_btn");
const number = document.querySelector(".number");
function Counter() {
let counter = 0;
this.increase = function () {
return ++counter;
};
this.decrease = function () {
return --counter;
};
}
const counter = new Counter();
increaseBtn.addEventListener("click", () => {
number.innerHTML = counter.increase();
});
decreaseBtn.addEventListener("click", () => {
number.innerHTML = counter.decrease();
});
</script>
</body>
생성자 함수 Counter는 increase, decrease 메소드를 갖는 인스턴스를 생성한다. 이 메소드들은 모두 자신이 생성됐을 때의 렉시컬 환경인 생성자 함수 Counter의 스코프에 속한 변수 counter를 기억하는 클로저이며 렉시컬 환경을 공유한다. 생성자 함수가 함수가 생성한 객체의 메소드는 객체의 프로퍼티에만 접근할 수 있는 것이 아니며 자신이 기억하는 렉시컬 환경의 변수에도 접근할 수 있다.