“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.
MDN의 정의입니다.
여기서 렉시컬 환경이 무엇인지 생소합니다.
렉시컬 스코프란 함수가 선언이 되는 위치에 따라서 상위 스코프가 결정되는 스코프입니다.
클로저의 상황 자체를 서술하는 정의입니다.
내부함수는 외부함수의 변수를 참조하는데 외부함수의 수명에 다했음에도 내부함수는 외부함수의 변수에 참조 가능한 상태입니다.
const outer = function(){
const a = "내부변수";
const inner = function(){
console.log(a);
}
return inner;
}
const myFunc = outer();
myFunc();
// 전역컨텍스트를 객체화
'전역 컨텍스트': {
변수객체: {
arguments: null,
variable: ['outer','myFunc'],
},
scopeChain: ['전역 변수객체'],
this: window,
}
// outer 컨텍스트를 객체화
'outer 컨텍스트': {
변수객체: {
arguments: null,
variable: [{ a : '내부변수' },'inner'],
},
scopeChain: ['outer 변수객체','전역 변수객체'],
this: window,
}
// outer 컨텍스트를 객체화
"closure 컨텍스트": {
변수객체: {
arguments: null,
variable: null,
scopeChain: ['myFunc 변수객체', 'outer 변수객체', '전역 변수객체'],
this: window,
}
이 때 스코프 체인을 통해 outer 변수 객체에 접근할 수 있고 이를 통해 a라는 변수가 접근이 가능한 것입니다.
함수와 함수가 선언이 되었을 때 렉시컬 환경과의 조합입니다.
여기서 함수란 반환되는 내부 함수를 의미합니다.
그리고 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때 환경 밖에서도 접근할 수 있는 함수를 뜻합니다.
클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수다라고 말할 수 있습니다.
<!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 increase = (function () {
// 카운트 상태를 유지하기 위한 자유 변수
var counter = 0;
// 클로저를 반환
return function () {
return ++counter;
};
}());
incleaseBtn.onclick = function () {
count.innerHTML = increase();
};
</script>
</body>
</html>
counter라는 값을 전역상태로 놓을 경우 수정이 가능하게 됩니다.
이 값을 은닉화하지만 상태 유지가 가능하게 (이전 값을 기억하게) 하고 싶다면, 클로저를 활용할 수 있습니다.
function useState(initialValue) {
let _value = initialValue;
const state = () => _value;
const setState = (newValue) => {
_value = newValue;
};
return [state, setState];
}
const [count, setCount] = React.useState(1);
console.log(count()); // 1
setCount(2);
console.log(count()); // 2
useState의 원리가 되는 코드입니다.
클로저를 통해 간단하게 구현한 useState 함수입니다.
[state, setState]가 선언되는 시점에서 useState의 호출은 끝나게 되지만, 클로저가 내부의 _value 값을 기억하고 있기 때문에 이후에도 접근이 가능합니다.
가비지콜렉터에서 대상이 제외되기 때문에 클로저를 남용하는 것은 좋지 않습니다.
메모리 누수의 위험이 있을 수 있습니다.
https://blacklobster.tistory.com/7
https://www.zerocho.com/category/JavaScript/post/5741d96d094da4986bc950a0
https://poiemaweb.com/js-closure
https://enjoydev.life/blog/javascript/6-closure