[구현] document.getElementsByClassName(className)을 재귀함수로 구현하기

in #kr-dev6 years ago (edited)

getElementsByClassName(className)은 class의 이름을 이용해서 HTML 요소(element)들을 가져오는 메소드이다.

아래와 같은 html이 있다고 해보자.

<!DOCTYPE html>
<html>
<body>
<div class=“numberOne”>First div element.</div>
<div class=“numberOne”>Second div element.</div>
<button onclick=“myFunction()”>Try it</button>
<script>
function myFunction() {
var x = document.getElementsByClassName(“numberOne”);
x[0].innerHTML = “changed div class”;
}
</script>
</body>
</html>


위 html은 “Try it” 버튼을 클릭했을 때, 자바스크립트에 있는 함수가 작동하는데,

자바스크립트에서 var x = document.getElementsByClassName(“numberOne”);는

“numberOne” 이름의 class를 가지고 있는 요소들을 가져온 것을 변수 x라고 선언했다.

그리고 변수 x중 첫번째 값(x[0])의 내용을 “changed div class”로 바꾸라고 작성했다.

그러면, 위 html에서 x중 첫번째 값은<div class=“numberOne”>First div element.</div> 이고,

이 요소에서 “First div element.”가 “changed div class”로 바뀌게 된다.

위와 같이, class 이름을 사용해서 요소들을 가져올 수 있다.


<구현해야할 문제>

특정 class의 이름이 속한 요소들을 가져오고, 가져온 모든 요소들을 배열로 묶어서 리턴하라.

(즉, document.getElementsByClassName(className)와 같은 작동을 하는 함수를 구현하는 것이다.)


<알고리즘>

  • HTML의 <body>에 속한 element(요소)를 하나씩 선택한다.
  • 선택한 element가 class가 있고, 그 class가 className에 포함하면, 새로 만든 배열에 추가한다.
  • 또한, 그 선택한 element가 Child Node(자식 Node)가 있는지 확인한다.
  • 만약 있다면, 그 Child Node도 class가 있고, 그 class가 className에 포함하는지 확인한다.(이때, 재귀함수 사용)
  • 포함이 되어있다면, 새로 만든 배열에 추가한다.
  • 이런식으로, element내에 또 다른 element도 className에 포함하는 class가 있다면, 그 element들을 가져와 배열에 추가하는 방식이다.


<구현>

이제, document.getElementsByClassName(className)을 직접 구현해보자.


<1> HTML의 <body>와 빈 배열을 선언한다.

var bodyHtml = document.body; // <body>
var result = [];


<2> 재귀함수로 돌릴 함수를 선언한다.

var hasClass = function(bodyHtml) {
}


<3> 선택한 element가 class가 있고, 그 class가 className에 포함하면, 새로 만든 배열에 추가한다.

var hasClass = function(bodyHtml) {
// 특정 클래스 값을 제어하기 위해 classList 사용
if(bodyHtml.classList && bodyHtml.classList.contains(className)) {
result.push(bodyHtml); // 새로 만든 배열에 추가
}


<4> 또한, 그 선택한 element가 Child Node(자식 Node)가 있는지 없는지 확인한다.
만약 있다면, 그 Child Node를 재귀함수로 돌려, 위에서 했던 방식으로 element를 체크한다.

// 'hasChildNodes()' 메소드 사용해서,
// 선택한 element가 Child Node(자식 Node) 있는지 확인
if(bodyHtml.hasChildNodes()) {
// 자식 Node가 있다면, 각 자식 Node를 하나씩 빼서
for(var i = 0; i< bodyHtml.childNodes.length; i++) { 
// 재귀함수에 돌려서 특정 클래스 값이 있는지 확인
hasClass(bodyHtml.childNodes[i]); 
}
}


<5> 선택한 element가 className에 포함되어서, 추가된 최종 배열을 리턴한다.

hasClass(bodyHtml); // 재귀함수를 처음에 돌리기 위해, 재귀함수를 호출한다.
return result; // element들이 추가된 배열을 리턴한다.


<소스코드>

var getElementsByClassName = function(className
){
var bodyHtml = document.body; 
var result = []
var hasClass = function(bodyHtml) {
if(bodyHtml.classList && bodyHtml.classList.contains(className)) {
result.push(bodyHtml);
}
if(bodyHtml.hasChildNodes()) {
for(var i = 0; i< bodyHtml.childNodes.length; i++) {
hasClass(bodyHtml.childNodes[i]);
}
}
}
hasClass(bodyHtml);
return result;
};


위 소스코드는 재귀함수를 사용하기 위해 함수안에 (재귀) 함수를 사용했다.

사용된 함수를 호출하기 위해, 처음에는 document.body(bodyHtml)를 호출해서, 

함수를 돌리고,각 요소와 각 요소들의 각 자식 Node를 체크하면서 className에 속하는 

class를 가진 요소들을 불러오고, 그 불러온 요소들을 배열에 추가하여, 

최종적으로 배열을 리턴하는 함수를 구현했다.