2025. 5. 14. 09:00ㆍJavascript/Javascript
클로저에서든 어디서든 자바스크립트를 사용하다 보면 간혹 함수 자체를 반환하는 함수를 보게 되는 경우가 있다.
function hello() {
return function world() {
return 'hello world!';
}
}
const a = hello(); // function world
아니 뭐 대략 원리는 알겠다. 사용법도 알겠다. 그런데 대체 이러한 기법이 어디에 쓰이는 걸까? 왜 값을 반환하면 되는 걸 굳이 함수 안에 함수를 리턴시키는 건지? 지금부터 return function { ... }에 대한 실용 기법을 알아보자.
일반적인 이벤트 콜백 함수 등록 방법
여기 버튼이 3개 있는 웹 문서가 있다.
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="c1">C1</button>
<button id="c2">C2</button>
<button id="c3">C3</button>
<script>
</script>
</body>
</html>
이제 저 3개의 버튼마다 다음과 같이 이벤트리스너를 등록할 예정이다. addEventListener의 두 번째 인자에는 함수가 들어가기 때문에 익명함수로 처리해 주었다.
<body>
<button id="c1">C1</button>
<button id="c2">C2</button>
<button id="c3">C3</button>
<script>
document.getElementById('c1').addEventListener('click', function(){ console.log(1) });
document.getElementById('c2').addEventListener('click', function(){ console.log(1) });
document.getElementById('c3').addEventListener('click', function(){ console.log(1) });
</script>
</body>
코드 자체에는 문제가 없지만 가만히 보면 반복되는 코드가 발생한다. 따라서 동일한 결과를 반환하는 함수를 밖으로 빼 리팩토링하기로 한다. c라는 함수를 새로 만들고 이벤트리스너에 등록시키면 된다. 다만 알다시피 이벤트리스너 인자에는 함수 자체가 들어가야 한다. 만일 함수 인자 부분에 c()와 같이 넣게 되면 반환 값 자체가 들어가는 꼴이 되기 때문에 함수 실행이 되지 않기 때문이다.
<script>
function c() {
console.log(1);
}
document.getElementById('c1').addEventListener('click', c);
document.getElementById('c2').addEventListener('click', c);
document.getElementById('c3').addEventListener('click', c);
</script>
이벤트 콜백에 파라미터를 사용해야 하는 경우
그런데 만일 스펙이 변경되어서 각 버튼마다 다른 동작을 하도록 구현한다면 어떻게 해야 할까? 예를 들어 c1 버튼을 누르면 1이 출력되고 c3을 클릭했을 때에는 3이 출력되어야 한다면? 이는 함수에 파라미터를 줘서 파라미터 변수 값을 출력해 주면 되는 방법이다. 하지만 문제는 '어떻게 줘야 하는가'이다.
function c(n) {
console.log(n);
}
document.getElementById('c2').addEventListener('click', c(2));
위와 같이 하면 앞서 언급했다시피 return 값을 넣어버리는 꼴이 된다. 즉 addEventLister의 두 번째 인자를 c로 하면 파라미터를 줄 수가 없고 c(2)로 하면 함수 실행이 안 되게 된다. 하지만 사실 방법은 간단하다.
함수를 리턴하는 함수를 이용한 클로저
c()로 이벤트리스너 함수에 등록하면 동작이 이상하게 되는 이유는 이벤트리스너에는 함수가 등록되는 게 아니라 리턴 값이 들어가기 때문이다. 그럼 이 원리를 이용하면 된다. 호출한 함수에서 아예 함수 자체를 리턴시켜버리면 리턴 값이 곧 함수이게 되고 곧 함수 등록이 되지 않을까?
function c(n) {
return function(){
console.log(n);
}
}
document.getElementById('c1').addEventListener('click', c(1));
document.getElementById('c2').addEventListener('click', c(2));
document.getElementById('c3').addEventListener('click', c(3));
이렇게 하면 이벤트리스너는 함수가 리턴된 함수(클로저 처리가 된)를 등록하게 되는 꼴이 된다.
함수를 리턴하는 함수의 코드를 보다 간결하게 하기 위해 화살표 함수로 나타내면 다음과 같이 표현이 가능하다.
const c = (n) => () => { //화살표 함수가 화살표 함수를 리턴한다.
console.log(n);
}
document.getElementById('c1').addEventListener('click', c(1));
document.getElementById('c2').addEventListener('click', c(2));
document.getElementById('c3').addEventListener('click', c(3));
'Javascript > Javascript' 카테고리의 다른 글
[Javascript] && 연산자로 조건문 단축시키기 (1) | 2025.05.16 |
---|---|
[Javascript] Scope (1) | 2025.05.15 |
[Javascript] 조건문 활용하기 (0) | 2025.05.12 |
[Javascript] JSON 다루기 (0) | 2024.12.04 |
[Javascript] 객체 복사 방법, 얕은 복사와 깊은 복사 (0) | 2024.12.02 |