재귀 함수(recursive function)와 콜백 함수(callback function)

건둔덕 ·2023년 3월 1일
3

Javascript

목록 보기
27/28
post-thumbnail

재귀함수(recursive function)

재귀함수란?
재귀함수(recursive function)는 함수가 자기 자신을 호출하는 것을 말합니다. 즉, 함수가 실행 중에 자기 자신을 호출하여 문제를 해결하는 방법입니다. 이를 통해 반복문을 사용하지 않고도 문제를 해결할 수 있습니다.

재귀함수의 특징

  • 종료 조건은 필수
    재귀 함수는 자기 자신을 호출하기 때문에 종료 조건이 없으면 무한히 호출됩니다. 따라서, 재귀 함수에서는 반드시 종료 조건을 설정해야 합니다.

  • 작은 문제로 분할
    재귀 함수는 자기 자신을 호출하여 문제를 해결하기 때문에, 원래 문제를 더 작은 문제로 분할할 수 있어야 합니다.

  • 문제의 해결 방법이 동일
    재귀 함수에서는 자기 자신을 호출하여 문제를 해결하기 때문에, 문제를 해결하는 방법이 항상 동일해야 합니다.


function countdown(n) {
	for(var i = n; i >=0; i--) console.log(i);
}

countdown(10);

위의 예제에서 countdown 함수는 문제없이 잘 작동 합니다. 하지만 이 함수를 반복문 없이 구현할 때 위에서 설명한 재귀 함수를 사용하는 것 입니다.

function countdown(n) {
	if (n < 0) return; // 종료 조건
  	console.log(n);
  	countdown(n - 1); // 재귀 호출
}

countdown(10);

위의 예제는 반복문 없이 자기 자신을 호출하는 재귀 함수를 사용해서 반복되는 처리를 반복문 없이 구현 했습니다.

function factorial(n) {
	if (n <= 1) return 1; // 종료 조건
  
  	return n * factorial(n - 1); // 재귀 호출
}

factorial(5); // 5! = 5 * 4 * 3 * 2 * 1 = 120

위의 예제는 팩토리얼(계승)을 재귀 함수로 간단하게 구현한 코드 입니다.

팩토리얼(계승)이란 1부터 자신까지의 모든 양의 정수의 곱을 말합니다.

재귀 함수는 탈출 조건(종료 조건)을 반드시 만들어야 하며 탈출 조건이 없으면 함수가 무한 호출되어 스택 오버플로 에러가 발생하니 주의가 필요합니다.

대부분의 재귀 함수는 반복문으로 구현이 가능합니다.

function factorial(n) {
	if (n <= 1) return 1; // n이 1보다 작으면 1을 리턴
  
  	// 반환할 값을 담은 result 변수를 생성 하고 입력받은 수 n을 할당
  	var result = n; 
  
  	// 반복문 while 사용
  	// 조건: n을 1씩 감소하게 하고 n의 값이 0이 되면 0은 falsy 값이기 때문에 반복문이 멈춘다.
  	// 실행: result 값과 n을 곱해서 result 값에 넣어준다.
  	while (--n) result *= n;
  
  	return result;
}

factorial(5); // 5! = 5 * 4 * 3 * 2 * 1 = 120

위의 예제는 팩토리얼을 재귀 함수말고 반복문으로 구현한 함수 입니다.

재귀 함수는 반복되는 처리를 반복문 없이 구현할 수 있다는 장점이 있지만 무한 반복에 빠질 위험이 있고, 이로 인해 스택 오버플로 에러를 발생시킬 수 있으므로 주의해서 사용해야 합니다. 따라서 재귀 함수는 반복문을 사용하는 것보다 재귀 함수를 사용하는 편이 더 직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직 합니다.

콜백함수(callback function)

콜백함수란?
콜백 함수(callback function)는 다른 함수에게 인자(argument)로 전달되는 함수입니다. 이 함수는 호출되어 실행되는 것이 아니라, 다른 함수에서 특정 이벤트가 발생했을 때 호출됩니다.

function repeat(n) {
	for(var i = 0; i <= n; i++) console.log(i);
}

repeat(5); // 0 1 2 3 4 5

function oddRepeat(n) {
	for(var i = 0; i <= n; i++) {
    	if (i % 2) console.log(i);
    }
}

oddRepeat(5); // 1 3 5

위의 예제에서 repeat 함수는 매개변수를 통해 전달받은 숫자만큼 반복하며 console.log(i)를 호출하게 됩니다. 이때 repeat 함수는 console.log(i)에 강하게 의존하고 있어 다른 일을 할 수 없게 됩니다.

이 때문에 홀수만을 반복하게 하는 다른 작업을 하게 하고 싶다면 함수를 oddRepeat 처럼 새롭게 작성해줘야 합니다.

위의 예제의 함수들은 반복하는 일은 변하지 않고 공통적으로 수행하지만 반복하면서 하는 일의 내용은 다릅니다. 즉, 함수의 일부분만이 다르기 때문에 매번 함수를 새롭게 정의해야 합니다.

이 문제는 함수를 합성해서 사용하는 것으로 해결할 수 있습니다. 함수의 변하지 않는 공통 로직은 미리 정의해 두고, 경우에 따라 변경되는 로직은 추상화해서 함수 외부에서 함수 내부로 전달하면 됩니다.

// 고차 함수 (HOF: Higher-Order Function)
function repeat(n, f) {
	for(var i = 0; i <= n; i++) {
    	f(i);
    }
}

// 콜백 함수1
var logAll = function(i) {
	console.log(i)
}
// 콜백 함수2
var logOdds = function (i) {
	if (i % 2) console.log(i);
}

repeat(5, logAll); // 0 1 2 3 4 5
repeat(5, logOdds); // 1 3 5

자바스크립트는 일급 객체에 속하므로 매개변수를 통해 함수를 전달할 수 있습니다. 위의 repeat 함수는 더 이상 내부 로직에 의존하지 않고 외부에서 로직의 일부분을 함수로 전달 받아 수행하므로 더욱 유연한 구조를 가지게 됩니다.

이처럼 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수(Callback Function) 매개 변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수(HOF: Higher-Order Function)라고 합니다.

콜백 함수는 고차 함수에 의해 호출되며 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있습니다.

profile
건데브

0개의 댓글