정의
클로저의 정의는 클로저는 독립적인 변수를 가리키는 함수이며, 클로저 안에 정의된 함수는 만들어진 환경을 '기억한다',라고 MDN에서 정의하고 있습니다.
간단한 예제
function getClosure() {
var text = 'variable 1';
return function() {
return text;
};
}
var closure = getClosure();
console.log(closure()); // 'variable 1'
위처럼 getClosure()를 호출하면 getClosure 내부에서 선언된 변수는 사라지지 않고 제대로 된 값을 가지고 있는 것을 확인할 수 있는데, 만들어진 환경을 기억하고 있는 이 var closure 변수에 담긴 함수를 바로 클로저라고 합니다.
자세하게 클로저에 대해 이해하기 전에 스코프에 대해 알고 있어야 하는데, 코드 블록 {...} 내에서 변수에 접근할 수 있는 범위라고 생각하면 좋습니다.
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // ?
bar(); // ?
위 코드를 렉시컬 스코프(Lexical Scope)라고 하는데, 현재 스코프는 foo와 bar, 그리고 x 변수가 선언된 총 3개의 스코프가 존재합니다.
렉시컬 스코프는 함수를 선언한 시점에서 상위 스코프가 결정되고, 함수를 어디에서 호출하였는지 스코프 결정에 아무런 영향을 주지 않는 특징을 가지고 있는데요.
function bar()는 전역에서 선언되었고, 따라서 function bar()의 상위 스코프는 전역 스코프로 볼 수 있습니다.
function static(){
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // ?
bar(); // ?
}
마치 이런 모양의 스코프로 볼 수가 있는 것이지요.
따라서 위 예제에서 foo()와 bar()의 실행한 값으로 x의 값 1이 2번이 출력됩니다.
/**
* 함수 outerFunc는 호출하면 내부 함수 innerPrint를 반환한다.
* 그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
*/
function outerFunc() {
var x = 10;
var innerPrint = function () { console.log(x); };
return innerPrint;
}
// inner에는 innerPrint 함수가 담겨져 있다.
var inner = outerFunc();
// inner, 즉 innerPrint함수를 호출하면 outerFunc()에 있던 x=10이라는 변수의 값이 출력된다.
inner();
위 코드는
outerFunc()의 스코프
innerPrint()의 스코프
2개로 볼수 있는데 outerFunc은 innerPrint의 상위 스코프라고 하고, innerPrint는 outerFunc의 내부에 선언된 내부함수라고 합니다.
위 코드 처럼 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역변수에 접근할 수 있는데 이러한 함수를 클로저(Closure)라고 합니다.
클로저는 반환된 내부 함수가 자신이 선언되었을 때의 환경(외부에는 x=10이 있다라는 환경)인 스코프(Scope)를 기억하여 자신이 선언됐을 떄의 환경(Scope) 밖에서 호출되어도 그 환경(Scope)에 접근할 수 있는 함수를 말하는데, 간단하게 클로저는 자신이 생성될 때의 환경을 기억하는 함수라고 할 수 있습니다.
* 여기서의 outerFunc의 변수 x를 자유변수(Free variable)라고 합니다.
클로저는 외부함수가 이미 반환되었어도 외부함수 내의 변수를 필요로 하는 내부함수가 하나 이상 존재하는 경우 그 변수가 계속 유지되는 특징을 가지고 있습니다. (이때 내부함수가 접근하는 외부함수의 변수는 복사본이 아니라 실제 변수에 접근합니다.)
클로저는 보통 현재 상태를 기억하고 변경된 최신 상태를 유지하는 데에 주로 사용됩니다.
예제
<!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>
위 처럼 isShow라고 하는 지역 변수를 isShow ? block : none으로 체크하는 내부함수에서 바라보고 있는데, 이러한 구조를 클로저라고 합니다.
자세한 예제와 내용은 아래 링크를 참고해주세요.
참고
https://poiemaweb.com/js-scope
https://poiemaweb.com/js-closure
'FrontEnd > ES&JS 문법' 카테고리의 다른 글
[Javascript] 호이스팅이란? (0) | 2022.10.17 |
---|---|
[Typescript] 자주 쓰는 문법 정리 (1) | 2022.09.08 |
[Javascript] RxJS란? (0) | 2022.05.26 |
[ECMAScript] Javascript ES6 Spread, Rest 정리 (0) | 2021.12.10 |
[ECMAScript] Javascript ES6 기초 문법 정리 (0) | 2021.11.11 |