웹브라우저 JavaScript

노드 종류 API

노드 작업을 하게 되면 현재 선택된 노드가 어떤 타입인지를 판단해야 하는 경우가 있다. 이런 경우에 사용할 수 있는 API가 nodeType, nodeName이다. 

  • Node.nodeType
    node의 타입을 의미한다. 
  • Node.nodeName
    node의 이름 (태그명을 의미한다.)

Node Type

노드의 종류에 따라서 정해진 상수가 존재한다. 아래는 모든 노드의 종류와 종류에 따른 값을 출력하는 예제다.

for(var name in Node){
   console.log(name, Node[name]);
}

결과

ELEMENT_NODE 1 
ATTRIBUTE_NODE 2 
TEXT_NODE 3 
CDATA_SECTION_NODE 4 
ENTITY_REFERENCE_NODE 5 
ENTITY_NODE 6 
PROCESSING_INSTRUCTION_NODE 7 
COMMENT_NODE 8 
DOCUMENT_NODE 9 
DOCUMENT_TYPE_NODE 10 
DOCUMENT_FRAGMENT_NODE 11 
NOTATION_NODE 12 
DOCUMENT_POSITION_DISCONNECTED 1 
DOCUMENT_POSITION_PRECEDING 2 
DOCUMENT_POSITION_FOLLOWING 4 
DOCUMENT_POSITION_CONTAINS 8 
DOCUMENT_POSITION_CONTAINED_BY 16 
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32

아래 예제는 노드 종류 API를 이용해서 노드를 처리하는 예제다. 함수가 자기 자신을 호출하는 것을 재귀함수라고 하는데 본 예제는 재귀 함수의 예를 보여준다.

 

<!DOCTYPE html>
<html>
<body id="start">
<ul>
    <li><a href="./532">html</a></li> 
    <li><a href="./533">css</a></li>
    <li><a href="./534">JavaScript</a>
        <ul>
            <li><a href="./535">JavaScript Core</a></li>
            <li><a href="./536">DOM</a></li>
            <li><a href="./537">BOM</a></li>
        </ul>
    </li>
</ul>
<script>
function traverse(target, callback){
    if(target.nodeType === 1){
		//if(target.nodeName === 'A')
		callback(target);
		var c = target.childNodes;
		for(var i=0; i<c.length; i++){
			traverse(c[i], callback);		
		}	
	}
}
traverse(document.getElementById('start'), function(elem){
	console.log(elem);
});
</script>
</body>
</html>

 

댓글

댓글 본문
  1. 코리니
    20230103
  2. 헤밍웨이
    220825 재귀로 쓸수도 있군요.
  3. mary5544
    어렵긴 한데 이해는 했어요!!
  4. 임앤강
    2022-02-12 강의 감사합니다~
    어후 재귀 함수.. 어렵네요.. ㅎㅎㅎ
  5. 드림보이
    2021.12.28. 노드 종류 API 파트 수강완료
  6. pmxsg
    2021.12.22. 수강
  7. Grit
    감사합니다.
  8. choi
    완료
  9. labis98
    20210911 좋은 강의 감사합니다.
  10. 낭만고양이
    수강완료
  11. 낭만고양이
    수강완료
  12. 애플
    i<c.length;
    입니다
    대화보기
    • 이동훈
      너무 어렵당~ 일단 패스...
    • 박병진
      2020.12.08 완료. 오늘은 여기까지
    • 싸알
      완료~
    • 이준호
      완료
    • anne
      완료
    • 여러분 위 코드는 C에서와 같은 일반적인 재귀함수의 탈출 조건이 필요 없습니다.
      반복은 재귀함수에서 제어하지 않고, for문에서 c.length로 c를 받는 순간 정해집니다

      body태그의 child node1를 탐색...
      child node1의 child node2를 탐색... (body의 child node 전부 할때까지 반복)
      C언어 였다면 child 노드가 아닌 것은 조건문으로 메모리가 null이면 탈출했겠지만

      여기선 이미 구현되어 있는 var c=target.childNodes; 을 이용할 때
      이부분이 이미 정상적인 child node의 메모리를 보장하기 때문이에요.

      C 였다면 if (c == null) return; 이런 식의 조건이 있어야만 하지만,
      여기서는 이게 API니까, childNodes의 메모리가 절대로 null(정의되지않음)이 아닌거죠.

      너무 생소하시면 일단 이것만 기억하세요.
      이 API(childNodes)가 정상적인 child의 메모리를 찾아주지 않으면 존재 의미가 없겠지요.
      덕분에 우리는 그런 예외들을 고려하지 않거나, 덜하고 코딩 할 수 있어요.
      대화보기
      • 정승옥
        완료
      • 김진욱
        완료
      • function traverse() {
        var queue = new Array();
        queue.unshift(document.getElementById('start'));

        while(queue.length > 0){
        var top = queue.pop();
        console.log(top.nodeName);

        if(top.childNodes.length > 0) {
        for (var i = 0; i < top.childNodes.length; i++) {
        queue.unshift(top.childNodes[i]);
        }
        }
        }
        }
        traverse();
      • 준바이
        조금 더 첨언을 하자면 저는 basecase의 의미를 세우는 코드로 리버전하자면 코드 제일 윗줄에

        if(target.nodeType !== 1) {
        // base case
        return null;
        }

        로 잡아주면 좋을 것 같습니다. 재귀관련 예시 코드들 보면 탈출 조건을 최대한 빨리, 가독성 좋게 표현하는 것 처럼 보이기 때문입니다.
        대화보기
        • ㄴㅇ
          매개변수(parameter) 는 함수에 입력되는 값(input) 이라고 생각하시면 됩니다.
          함수는 이 값을 받아서 이리저리 가공을 한 후 결과(output) 를 뱉어내죠.
          대화보기
          • Coder
            매개변수......가 뭐지.....................
          • 생존코딩
            자식노드를 계속 탐색하다보면 언젠간 Element가 아닌 노드가 target 파라미터에 들어가게 됩니다(텍스트 노드가 target 파라미터에 들어가겠죠?). 그러면 if(target.nodeType === 1) 조건문을 건너뛰고 함수가 그대로 종료되면서 더 이상 callback함수를 호출하지않습니다.
            대화보기
            • ㅈㄱㅎㅅ
              재귀함수는 무한반복을 막기 위해 자신을 정지시키는 코드가(base case) 꼭 들어가야된다고 하던데 여기에서 그 부분은 어딘가요?

              function traverse(target, callback){
              if(target.nodeType === 1){
              //if(target.nodeName === 'A')
              callback(target);
              var c = target.childNodes;
              for(var i=0; i<c.length; i++){
              traverse(c[i], callback);
              }
              }
              }
            • 굼벵이
              완료
            • 모든일이일사천리
              Done : 19/11/24 3PM
            • 정홍
              완료
            • 2019-10-15 8:35pm 완료
            • 재귀함수 코드 관련하여 보충 설명 해주실 수 없나요. 이전 기본 자바스크립트 수업에서의 callback 예제랑 동떨어진 것처럼 느껴져서 .. 이해가 잘 안되요.
            • 지나가는 나그네
              A,B,C로 간단히 말씀드릴게요

              A가 B 호출
              A 잠깐 대기
              B가 C 호출
              B 잠깐 대기
              C에서 탈출조건 성립 되돌아간다.
              B 다시 재개(재귀함수 밑 부분 코드 실행)
              A 다시 재개 (재귀함수 밑 부분 코드 실행)

              이것을 1~100개 까지 있다고 친다면
              일단 100까지 쭉 갑니다(100이 최초 탈출조건 성립이라 가정시)
              탈출 조건이 성립되면 이제 다시 100~1까지 나머지 코드들을 실행하면서 돌아옵니다.

              자료구조를 공부하시면 넓은 관점에서 보실수 있을거에요
              대화보기
              • 훈민정
                재귀함수 보충 수업 부탁드립니다. 다른건 다 이해했는데 재귀함수는 도저히 이해가 안돼네요..
              • GOD IS ALWAYS GOOD
                밑에 계신 분이랑 똑같은 질문인데요 ㅠㅠ

                처음 start 의 childNodes에 대한 for문이 돌면서 traverse가 그 안에서 실행되는데

                그럼 다시 또 그 childNodes에 대한 childNodes를 가져와서 for를 돌리고(아직 start는 첫번째 자식밖에 돌지 못한상태) 그 childNode가 또 childNode 또돌리고

                1~5 까지 있다고 한다면

                1
                12

                2
                23

                3
                34

                4
                45

                5

                345

                2345

                1
                12
                123

                34

                45

                5
                ....

                뭐 이런식이 아닌가요???ㅜㅜㅜ
              • 이채
                알림이 떠서 들어와봤는데 3주쯤 지났다고 벌써 기억이 잘 안 나네요..ㅎㅎㅎㅎ
                제 능력 부족으로 완전히 이해했다고 선뜻 대답하긴 어렵지만ㅠ.ㅠ많은 도움이 되었습니다 감사합니다^^
                대화보기
                • 재귀함수
                  1. target을 출력하고, target의 childNodes에 대해서 for문을 돌며 다시 traverse 구문을 수행합니다.
                  childeNodes의 childeNodes를 돌면서 결국 전체 엘리멘트를 검색합니다.

                  2. 조건문의 대상으로 callback 한줄만 거는 이유는, 전체 엘리멘트의 탐색을 위해서입니다.
                  (target이 A태그가 아니면 출력은 하지 않지만, 자식에 A태그가 있다면, 탐색해야 하기 때문에 출력에만 조건을 겁니다.)

                  3. A태그 조건문의 범위를 끝까지 걸었을 때,
                  - 첫번째 target은 body인데 A가 아니므로 출력하지 않습니다.
                  - 원래대로라면 출력만 하지 않고, 밑의 for문을 돌며 body의 childNodes를 다시 검사합니다.
                  하지만, 조건문의 범위로 인해 탐색도 안하고 종료됩니다.
                  - 결과적으로 아무것도 출력되지 않습니다.
                  대화보기
                  • 이채
                    var c = target.childNodes;
                    for(var i=0; i<c.length; i++){
                    traverse(c[i], callback);
                    }
                    이 부분에서 for문을 반복하면 c[0], c[1], c[2]... 이런 식으로 body 바로 아래의 자식노드만 나오는 것은 아닌건가요?
                    콘솔에서 start.childNodes를 치면 [text, ul, text, script, text] 이렇게만 나오더라구요.
                    traverse에 넣었기 때문에 다시 c로 돌아가서 다시 childNodes의 childNodes가 되는 것인지.. 개념이 안 잡히다 보니 돌려봐도 헷갈립니다ㅠㅠ

                    또 주석처리한
                    //if(target.nodeName === 'A')
                    callback(target);
                    이 부분에서 A태그만 선택하는 것은 callback(target) 한줄만인 이유가 무엇인지 이해가 잘 안 갑니다.

                    function traverse(target, callback){
                    if(target.nodeType === 1){
                    //if(target.nodeName === 'A') {
                    callback(target);
                    var c = target.childNodes;
                    for(var i=0; i<c.length; i++){
                    traverse(c[i], callback); }
                    }
                    }
                    }
                    이런 식으로 A태그 부분을 끝까지 묶어버리니 아무 태그도 뜨질 않네요.
                    처음 nodeType === 1 이 부분은 끝까지 묶어서 작동시키는데, A태그만 분류할 때는 한 줄만 실행하는게 어떤 점에서 차이가 있는건지, 댓글을 읽어봐도 완전히 와닿지가 않습니다ㅠ.ㅠ고수분들 도와주세요
                  • 성기훈
                    body태그와 ul태그 사이에 줄바꿈이 들어가 있어서 그렇습니다.
                    body태그와 ul태그 사이에 띄어쓰기든 줄바꿈이든 공백이 들어가게 되면 그걸 글자로 인식해서 #text라고 나타내고
                    실제로 body태그와 ul태그를 딱 붙여주면 공백이 없게 되어 #text가 사라질 겁니다.
                    우리는 편의상 줄바꿈을 넣지만 Node는 공백도 자식노드로 인식하여 #text값이 나오는 거지요.
                    대화보기
                    • 흑흑
                      1번 영상에서

                      body 태그의 첫번 째 차일드가 왜 text 인지 이해가 안됩니다.......

                      혹시 아시는분???
                    • JuicyFresh
                      감사합니다.
                    • 공부중
                      if문 바로 다음 한 줄 코드는 암시적으로 if문의 내용이라고 판단하여 중괄호 생략 가능합니다. 두 줄 부터 중괄호를 쳐서 if문 안의 내용이라는 것을 명시해줘야 하구요. for문, while문도 마찬가지 입니다.
                      대화보기
                      • 김수
                        callback....0901...
                        너무어려우 ㅓㅠㅠ히잏ㅇ
                      • 생선과고양이
                        20140426 3번 돌려봐도 이해가 안가서 이번강의는 패스 합니다
                      • 인자
                        function traverse(target, callback){
                        if(target.nodeType === 1){
                        if(target.nodeName === 'A')
                        callback(target);
                        var c = target.childNodes;
                        for(var i=0; i<c.length; i++){
                        traverse(c[i], callback);
                        }
                        }
                        }
                        여기서 if(target.nodeName === 'A') 뒤 중괄호가 생략되있는데 댓글들 보면서 생각해봤습니다. 중괄호를

                        function traverse(target, callback){
                        if(target.nodeType === 1){
                        if(target.nodeName === 'A'){
                        callback(target);
                        var c = target.childNodes;
                        for(var i=0; i<c.length; i++){
                        traverse(c[i], callback);
                        }
                        }
                        }
                        }
                        이런식으로 밑에 for문까지해버리게되면 body태그에서 child노드가 a인것을 찾고 그 child노드, 즉 a태그안에 있는 childnode를 찾아 나가는거기때문에 body태그 바로밑에 a태그가 childnode로 없기때문에 결과가 아무것도 안나오는 것 같습니다. body-ul-li-a이런식으로 거쳐서 나중에 나오기때문이죠.
                      • 인자
                        if(target.nodeName === 'A')
                        callback(target);
                        여기서 중괄호 묶어 줘야 하지 않나요?
                        if(target.nodeName === 'A'){
                        callback(target);
                        }
                        이런식으로요.
                      • 박인호
                        12-29
                        수강완료.
                        재귀함수가 처음봤을때 이해가 잘 안 됐었는데
                        보다보니 어떻게 돌아가는 녀석인지 알겠네요.
                        감사합니다.
                      • 도레미
                        이번 내용 좀 어려웠지만,, 다음에 복습하러 다시 올게요!
                        그치만 이번 강의 방식 너무 중요하고 감사해요!... 실무에서,, 어떻게 코드를 작성할 것인가하는 생각을 같이 따라갈 수 있어서요!
                      • 박민경
                        조건문에서 {}이렇게 묶지 않은 두번째는 묶어주면 콘솔창에 아무것도 안뜨는데 이유가 뭔가요?
                        언제 묶어야 하고 언제 안묶어요 되는 건가요?
                      • Byungsoo Kim
                        감사합니다.
                      • 수복
                        다시 봐야겠군요...
                      버전 관리
                      egoing
                      현재 버전
                      선택 버전
                      graphittie 자세히 보기