함수가 자기 자신을 호출하는 행위를 재귀 함수라고 하며 내부적으로 자기 자신을 호출하면 특정 문제를 해결할 수 있다.
function fact(n) {
if (n <= 1) {
return 1;
}
return n*fact(n-1);
}
위 예제는 n의 값으로 숫자 5가 주어졌을때, 54321=120 의 값이 반환되는 함수로 재귀의 대표적인 특성을 뽑을 수있다.
종료 : false의 값이 들어오면 멈춰야 한다.
n의 값이 1보다 작을 경우 멈추는 조건을 추가해줘야 한다.
if(n <= 1)
실행 : true의 값이 들어오면 재귀를 호출한다.
n의 값이 1보다 큰 'if(n <= 1)'의 false가 되는 구문이 실행된다. 해당 구문이 실행되는 조건은 n이 1이 되어 if의 값을 만족할때까지 실행된다.
재귀 : 자기 자신을 호출해 특정 문제를 해결한다.
2번이 if문을 만족할때까지 계속 실행될 수 있기 때문에
반복문을 사용하지 않고 자기 자신을 호출함으로써 조건문이 만족할때까지 실행된다.
<p class=”targetClassName”></p>
<p><p class=”targetClassName”></p></p>
<p><div class=”somediv”><div class=”innerdiv”><span class=”targetClassName”>hi</span></div></div></p>
targetClassName클래스 이름을 가진 노드를 반환하는 document.getElementsByClassName을 구현하는 것을 목표로하는 재귀 함수를 구현해보자
특정 class의 이름이 속한 요소들을 가져오고, 가져온 모든 요소들을 배열로 묶어서 리턴하라.
(즉, document.getElementsByClassName(className)와 같은 작동을 하는 함수를 구현하는 것이다.)
<알고리즘>
<구현>
1) HTML의 와 빈 배열을 선언한다.
var bodyHtml = document.body; // <body>
var bin = [];
2) 재귀함수로 돌릴 함수를 선언한다.
var check = function(bodyHtml) {
}
3) 선택한 element가 class가 있고, 그 class가 className에 포함하면, 새로운 배열에 추가한다.
var check = function(bodyHtml) {
// 특정 클래스 값을 제어하기 위해 classList 사용
if(bodyHtml.classList &&
bodyHtml.classList.contains(className)) {
bin.push(bodyHtml); // 새로 만든 배열에 추가
}
4) 또한, 그 선택한 element가 childNode(자식 Node)가 있는지 없는지 확인한다.
만약 있다면, 그 child Node를 재귀함수로 돌려, 위에서 했던 방식으로 element를 체크한다.
//'hasChildNodes()' 메소드를 사용해서,
// 선택한 element가 child Node(자식 Node) 있는지 확인
if(bodyHtml.hasChildNodes()) {
// 자식 Node가 있다면, 각 자식 Node를 하나씩 빼서
for (let i = 0; i < bodyHtml.childNodes.length; i++) {
// 재귀 함수에 돌려서 특정 클래스 값이 있는지 확인
check(bodyHtml.childNodes[i]);
}
}
5) 선택한 element가 className에 포함되어서, 추가된 최종 배열을 리턴한다.
check(bodyHtml); // 재귀함수를 처음에 돌리기 위해, 재귀함수를 호출한다.
return bin; // element들이 추가된 배열을 리턴한다.
const getElementByClassName = function(className) {
const bodyHtml = document.body;
const bin = [];
let check = function(bodyHtml) {
if (bodyHtml.classList && bodyHtml.classList.contains(className)) {
bin.push(bodyHtml);
}
if (bodyHtml.hasChildNodes()) {
for(let i = 0; i < bodyHtml.childNodes.length; i++) {
check(bodyHtml.childNodes[i]);
}
}
}
check(bodyHtml);
return bin;
}
위 소스코드는 재귀함수를 사용하기 위해 함수안에 (재귀) 함수를 사용했다. 사용된 함수를 호출하기 위해, 처음 document.body(bodyHtml)를 호출해서, 함수를 돌리고, 각 요소와 각 요소들의 각 자식 Node를 체크하면서 className에 속하는 class를 가진 요소들을 불러오고,
그 불러온 요소들을 배열에 추가하여, 최종적으로 배열을 리턴하는 함수를 구현했다.