매번 매번 매번 봐도 남에게 설명해주기 어려운 그것 .. 클로저
클로저는 외부 변수를 기억하고 이 외부 변수에 접근할 수 있는 함수를 의미한다.
클로저는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가리키며 캡슐화나 은닉화가 핵심이다.
스코프 체인으로 표현되기도 한다.
들어가기 앞서, 스코프
에 대해 간단히 설명.
스코프
란, 변수와 함수의 유효범위를 말한다.아래는 내부 함수에서 외부 함수에 직접 접근할 수 있는 예시이다.
function init() {
var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
function displayName() { // displayName() 은 내부 함수이며, 클로저다.
alert(name); // 부모 함수에서 선언된 변수를 사용한다.
}
displayName();
}
init(); // 출력결과: alert("Mozilla")
init()
은 지역 변수 name
과 함수 displayName()
을 생성한다.displayname()
은 init
안에 정의된 내부 함수이며 init()
함수 본문에서만 사용할 수 있다.displayName()
내부엔 자신만의 지역 변수가 없다는 점인데,displayName()
역시 부모함수 init()
에서 선언된 변수 name
에 접근할 수 있다!위 코드를 실행하면 displayName()
함수 내의 alert()
문이 부모 함수에서 정의한 변수 name
의 값을 성공적으로 출력한다.
어휘적 범위지정(lexical scoping)
의 한 예시이다.아래는 함수 내부에서 선언된 변수를 외부에서 직접 접근할 수 없도록 하고자 할 때 클로저를 활용한 예시이다.
function counter() {
let count = 0;
function increaseCount() {
count++;
console.log(count);
}
return increaseCount;
}
const myCounter = counter();
myCounter(); // 1
myCounter(); // 2
counter()
함수는 increaseCount()
함수를 반환한다. 이때 increaseCount()
함수는 외부에서 선언된 변수 count
에 접근할 수 있도록 클로저를 형성한다.myCounter
변수에 counter()
함수를 실행한 결과를 할당하고, myCounter
함수를 호출할 때마다 counter
변수가 증가하도록 구현이 되어있는 것이다.count
변수를 외부에서 직접 접근할 수 없게 만들고, 함수를 통해 안전하게 증가하는 변수를 만들 수 있다.다음은 데이터 은닉화를 위해 클로저를 활용한 예시이다.
<!DOCTYPE html>
<html>
<body>
<button id="plus">+</button>
<p id="count">0</p>
<script>
let plusBtn = document.getElementById('plus');
let countTxt = document.getElementById('count');
let plus= (function () {
// 카운트 상태를 유지하기 위한 자유 변수
let count = 0;
// 클로저를 반환
return function () {
return count++;
};
}());
plusBtn.onclick = function () {
countTxt .innerHTML = plus();
};
</script>
</body>
</html>
위의 코드는 숫자를 하나씩 카운트하는 코드인데, 여기서 count
라는 변수가 만약 전역변수로 선언되어 카운팅되게 만들어졌다면 이는 위험한 프로그램이 될 것이다.
그런데 위처럼 클로저를 이용하면 내부로 철저히 숨길 수 있어 은닉화가 가능하다.