📌 클로져(Closure)는 무엇이며, 어떻게/왜 사용하는지 설명해주세요.
클로져(Closure )란 함수와 그 함수가 선언되었을 때의 어휘적 환경(Lexical environment )과의 조합이다.
어휘적 환경(Lexical scope )이란 선언된 변수, 함수 등이 사용가능 하고 영향을 미치는 범위를 말한다.
이는 MDN에 나온 클로져의 정의이다. 그런데 조합이라고하니 이해하기가 힘들다.
예제를 통해 클로져를 이해해보자
function test() {
var item = 0;
// inner 함수는 test의 내부 함수이며 test의 지역에 접근할 수 있다.
function inner() {
item++;
return item;
}
// inner 함수 반환
return inner;
}
var test_function_obj = test();
test_function_obj();
test_function_obj();
test_function_obj();
함수의 실행 후 지역 변수는 함수가 처리되는 동안에만 존재한다.
따라서, test()
의 지역 변수 item
은 접근할 수 없어야 한다.
실제로 실행해보면 아래와 같다.
var test_function_obj = test();
// 유효 범위의 어휘적 환경을 유지하기 때문에 item
test_function_obj(); // 1을 반환
test_function_obj(); // 2을 반환
test_function_obj(); // 3을 반환
item
변수에 접근이 되며 심지어 변수를 기억하기 까지 하여 item
의 값이 올라가는 것을 볼 수 있다. 이는 inner
가 클로져이기 때문이다.
JavaScript는 클로져를 형성하여 유효 범위 내의 모든 지역 변수, 참조하는 상위 지역 변수를 기억하게 된다.
즉, 클로져란 자신이 선언됬을 때 환경인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수이다.
내부함수가 호출되면 자신의 실행 컨텍스트가 call stack에 쌓임
변수 객체(Variable Object )와 스코프 체인(Scope chain ) 그리고 this
에 바인딩할 객체가 결정된다. 이때, 스코프 체인은 다음순으로 바인딩 한다.
- 전역 객체와 함수의 스코프를 가리키는 활성 객체
- 함수 자신의 스코프를 가리키는 활성 객체
스코프 체인이 바인딩한 객체가 어휘적 환경이 된다.
스코프 체인은 아래와 같다.
클로져는 어떤 데이터(어휘적 환경)와 그 데이터를 조작하는 함수를 연관시킨다.
아래와 같은 작업을 할 수 있다.
현재 상태를 기억 및 변경된 최신 상태를 유지하게 할 수 있다.
var toggle = (function () {
var isActive = false; // 현재 상태를 나타내는 변수
// 클로저를 반환
return function() {
document.body.style.backgroundColor = isActive ? "red" : "green";
isActive = !isActive;
}
});
var myToggle = toggle();
debouncer. throttler 를 만들때도 유리하다.
클로져를 이용하면 캡슐화하여 정보를 은닉할 수 있다.
var myFunction = function() {
// private 속성처럼 외부에서 직접 이 변수를 변경할 수 없음
var privateValue = 0;
// privateValue 를 증가 시키는 클로져
this.plus = function() {
privateValue++;
}
// privateValue 를 감소 시키는 클로져
this.minus = function() {
privateValue++;
}
// privateValue 값을 반환하는 클로져
this.get = function() {
return privateValue;
}
}
// new 연산자로 생성
var test = new myFunction();
test.plus(); // 0 -> 1
console.log(test.get()); // 1 출력
test.plus(); // 1 -> 0
console.log(test.get()); // 0 출력
test.privateValue = 3; // test에 privateValue 가 들어가나 this.privateValue 와 다름
test.get() // 0
⚠️ 클로저가 참조하는 외부 함수의 변수는 본사본이 아닌 값을 직접 참조하기 때문에 계속해서 인스턴스를 만들게 되면 메모리 낭비가 심할 수 있다. (메모리 누수)
💡 메모리 누수(memory leak): 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상