제 생각으로는 외부함수를 선언하고 외부함수 스코프에 있는 변수에 접근을 막는다(폐쇄)의 의미를 담아 이름을 지었다고 생각합니다
클로저 함수는 외부 함수의 실행이 끝나더라도 외부 함수 내 변수를 사용할 수 있다.
클로저는 이처럼 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게 하는 폐쇄성을 갖는다.
function OutFn() { //외부함수
var i = 0;
function increment() {
i = i + 1;
}
function getCount() {
increment();
return i;
}
return {
InFn : getCount //내부함수
}
};
클로저 함수를 사용해 내부 변수를 사용하면서, 함수 호출을 통해 변수를 수정해 준다면 외부에서의 접근 없이 사용할수 있다.
클로저를 통해 데이터와 메소드를 묶어 다닐수 있기에 클로저는 모듈화에 유리하다
마치 객체를 생성해 메소드를 부르는것과 같다
function OutFn() { //외부함수
var i = 0;
function increment() {
i = i + 1;
}
function getCount() {
increment();
return i;
}
return {
InFn : getCount //내부함수
}
};
var func = OutFn();
console.log(func.InFn()); //1
console.log(func.InFn()); //2
console.log(func.InFn()); //3
내부함수(InFn)을 통해 외부함수Scope에 존재하는 var i에 접근이 가능한것을 말한다.
일반적으로는 함수가 끝나면 스택이 빠지고 지역변수,메소드 등 내용물이 빠지는것이 기본이다.
하지만 클로저는 내부함수가 외부함수 스코프에 존재하는 변수를 참조하고 있기때문에 외부함수가 종료가 되도 값이 사라지지 않는다 → 실행컨텍스트 개념과 일치함(자신이 선언되었을때의 환경(Lexical Environment)에서의 스코프를 기억하기 때문에 접근이 가능합니다.)
자바스크립트는 변수가 참조하고 있으면 함수가 종료되도 해당 참조를 남겨놓기때문에 사라지지 않는다.
내부함수에서 i를 참조하고 있지 않다면? 존재할 이유가 없다
i를 참조하고 있지 않는다면 어짜피 내부함수에서도 사용하지 않는것이고 외부함수를 호출과 동시에 사라진다.
결국에는 직접적으로 접근이 불가능한 것이다.
연관검색어를 띄운다고 가정해보자
사용자가 글자를 입력할때(키보드이벤트가 발생할때)마다 쿼리를 날리게되면 api 비용이 그만큼 나오는데, 사용자는 필요한 정보를 검색할때 보통 타자를 계속 치다가 완료가되면 멈추게된다.
그러면 사용자가 계속 입력중이면 쿼리를 안보내고, 키보드를 일정시간 치지 않았을때 연관검색어를 찾아주면 비용을 줄일수 있지 않을까? → 이것을 해결한것이 디바운스 개념이다.
<body>
<input type="text" onkeyup="processChange()" />
</body>
<script type="text/javascript">
//디바운스
function debounce(func, timeout =1000) {
let timer;
return (...args) => {
clearTimeout(timer); //사용자가 입력을 하게되면 타이머를 초기화하고
timer = setTimeout(() => {
func() -> saveInput();
}, timeout);
};
}
function saveInput() {
console.log('Saving data');
}
const processChange = debounce(() => saveInput());
함수는 호이스팅되어 사용되기때문에 선언순서는 상관없다.
debounce라는 외부함수를 processChange에 값으로 넣고 쿼리를 날릴 함수와 timeout을 변수로 준다.
processChange가 실행될때마다 이벤트가 실행되면서 아래 코드가 실행된다.
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
timer를 참조하고 있기때문에 외부함수가 끝나도 내부함수내에 존재하고 있다.
이를 통해 timer가 값이 존재해 setTimeout이 실행중인지 알수 있다.
processChange(e.target.value)
위처럼 사용하고 핸들러를 통해 이벤트값을 넘겨주면 내부함수의 (…args)에는 이벤트 매개변수가 들어가게된다.
const DeBounce = (callback: (query: string) => Promise<void>,delay : number) =>{
let timer : NodeJS.Timeout
return function (query : string)
{
clearTimeout(timer)
timer = setTimeout( ()=>{
callback(query)
},delay)
}
}
export default DeBounce
const OnchangeHandler = (e : React.ChangeEvent<HTMLInputElement>) =>{
setInputValue(e.target.value)
debounceHandler(e.target.value)
}
const debounceHandler = useCallback(DeBounce((input) => sendQuery(input), 500),[]);