7 분 소요

📝웹 브라우저의 빌드

먼저 DOM을 이해하기 위해 웹 페이지의 빌드 과정을 먼저 알아보겠습니다.

  • 크롬, 사파이, 엣지, 파이어폭스 등의 브라우저가 공장 이라고 예를 들어보겠습니다 . 그리고 HTML 문서는 공장에 보내는 주문서라고 예를 들어보겠습니다.

    이 주문서에는 내가 원하는 웹페이지의 요소들과 구조가 설계도처럼 표현돼어있습니다.

    예를 들어 body 태그 안에 header 태그와 main 태그가 있고 header 안에는 ul에 묶여서 li가 몇개 들어가 있습니다.

    이러한 구체적인 구조를 HTML이란 주문서에 담아서 브라우저 라는 공장으로 보냅니다.

    주문서를 받은 브라우저 공장에서는 주문서의 HTML 요소들인 body, div, li, span, 텍스트 등을 실제 제품들로 제작하게 됩니다.

    예를 들어 HTML 주문서를 보면 <input text="text" class="input"> 와 같이 글을 넣어주게 되면 이게 브라우저 공장으로 가면 문자열이나 숫자를 입력받거나 체크박스로 온/오프 박스를 하는 등 입력을 받고 그 값을 value로 내보낼 수 있는 그러한 기능들을 다 갖춘 실제 제품 input 오브젝트로 만들어지게 됩니다.

    제품으로 만들어 지는 과정은 웹브라우저는 HTML 문서를 해석하고, 화면을 통해 해석된 결과를 보여줍니다. 해석한 HTML 코드를 화면을 통해 보여주는 과정을 “렌더링” 이라고 합니다.

    브라우저는 HTML 코드를 해석해서 요소들을 트리 형태로 구조화해 표현하는 문서(데이터)를 생성합니다.

    이를 DOM이라 하며, 브라우저는 DOM을 통해 화면에 웹 콘텐츠들을 렌더링합니다.

📝DOM(Document Object Model)이란?

  • 웹 브라우저가 HTML 문서를 읽어 들이면 위에 그림처럼 Document 객체로 시작하는 DOM 트리가 만들어집니다. 트리 자료구조에서는 트리를 구성하고 있는 객체 하나를 노드(Node)라고 부릅니다. 위 그림에서 볼 수 있는 기본적인 세 가지 노드를 먼저 정리하겠습니다.
    1. 문서 노드: 보라색 도형으로 표현된 제일 위에 있는 노드가 문서노드입니다. 트리의 최상위 계층이면서 전체 문서를 가리키는 Document 객체입니다. document로 참조할 수 있으며 DOM 트리로 웹 페이지를 접근하는 시작점입니다.
    2. 요소 노드: 파란색 도형으로 표현된 노드들이 요소 노드입니다. HTML 태그에 해당되는 요소들입니다. 요소 노드는 속성 노드와 택스트 노드를 자식으로 가질 수 있습니다.
    3. 텍스트 노드: 초록색 도형으로 표현된 노드들이 텍스트 노드입니다. HTML 태그 안에 있는 텍스트들이 텍스트 노드이며 이들은 요소 노드와 달리 자식 노드를 가질 수 없습니다.

img

트리 자료구조는 부모-자식 관계라고 부릅니다.

트리 자료 구조에서는 기준보다 위에 있는 노드를 부모 노드라고 부르며 같은 층위에 존재하는 옆에 노드를 형제 노드라고 부릅니다. 부모 노드보다 위에 있는 노드를 조상 노드라 하고 최상위에 있는 더 이상 부모 노드가 없는 노드를 루트(뿌리)라고 합니다.

주요 노드 프로버티

  • DOM 노드는 종류에 따라 각각 다른 프로퍼티를 지원합니다. 태그 <a>에 대응하는 요소 노드엔 링크 관련된 프로퍼티를, <input>에 대응하는 요소 노드엔 입력 관련프로퍼티를 제공하죠. 텍스트 노드는 요소 노드와 다른 프로퍼티를 지원하는 것은 말할 필요도 없습니다. 그런데 모든 DOM 노드는 공통 조상으로부터 만들어지기 때문에 노드 종류는 다르지만, 모든 DOM 노드는 공통된 프로퍼티와 메서드를 지원합니다.

    DOM 노드는 종류에 따라 대응하는 내장 클래스가 다릅니다.

    계층 구조 꼭대기엔 EventTarget이 있는데, Node는 EventTarget을, 다른 DOM 노드들은 Node 클래스를 상속받습니다.

  • 각 클래스는 다음과 같은 특징을 지닙니다.

    • EventTarget – 루트에 있는 ‘추상(abstract)’ 클래스로, 이 클래스에 대응하는 객체는 실제로 만들어지지 않습니다. EventTarget가 모든 DOM 노드의 베이스에 있기때문에 DOM 노드에서 ‘이벤트’를 사용할 수 있습니다. 자세한 내용은 곧 다룰 예정입니다.

    • Node – 역시 ‘추상’ 클래스로, DOM 노드의 베이스 역할을 합니다. getter 역할을 하는 parentNode, nextSibling, childNodes 등의 주요 트리 탐색 기능을 제공합니다. Node 클래스의 객체는 절대 생성되지 않습니다. 하지만 이 클래스를 상속받는 클래스는 여럿 있습니다. 텍스트 노드를 위한 Text 클래스와 요소 노드를 위한 Element 클래스, 주석 노드를 위한 Comment클래스는 Node클래스를 상속받습니다.

    • Element – DOM 요소를 위한 베이스 클래스입니다. nextElementSibling, children 이나 getElementsByTagName, querySelector 같이 요소 전용 탐색을 도와주는 프로퍼티나 메서드가 이를 기반으로 합니다. 브라우저는 HTML뿐만 아니라 XML, SVG도 지원하는데 Element 클래스는 이와 관련된 SVGElement, XMLElement, HTMLElement 클래스의 베이스 역할을 합니다.

    • HTMLElement

      – HTML 요소 노드의 베이스 역할을 하는 클래스입니다. 아래 나열한 클래스들은 실제 HTML 요소에 대응하고 HTMLElement 를 상속받습니다.

      • HTMLInputElement<input> 요소에 대응하는 클래스
      • HTMLBodyElement<body> 요소에 대응하는 클래스
      • HTMLAnchorElement<a> 요소에 대응하는 클래스
      • 이외에도 다른 클래스가 많은데, 각 태그에 해당하는 클래스는 고유한 프로퍼티와 메서드를 지원합니다.

  • nodeType

    • nodeType 프로퍼티는 DOM 노드의 ‘타입’을 알아내고자 할 때 쓰이는 구식 프로퍼티입니다.

      각 노드 타입은 상숫값을 가집니다.

      • 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
        
        • 예시:
      <body>
        <script>
          let elem = document.body; // 타입을 알아봅시다. alert(elem.nodeType); //
          1 => 요소 노드 // 첫 번째 자식 노드 alert(elem.firstChild.nodeType); //
          3 => 텍스트 노드 // 문서 객체의 타입 확인 alert( document.nodeType ); //
          9 => 문서 객체
        </script>
      </body>
      

      모던 자바스크립트에선 노드의 타입을 instanceof나 클래스 기반의 테스트를 이용해 확인하는데, 가끔은 nodeType를 쓰는 게 간단할 때도 있습니다. nodeType은 타입 확인 하는 데만 쓸 수 있고 바꾸지는 못합니다.

  • nodeName, tagName

    • nodeName이나 tagName 프로퍼티를 사용하면 DOM 노드의 태그 이름을 알아낼 수 있습니다.

      예시:

      alert( document.body.nodeName ); // BODY
      alert( document.body.tagName ); // BODY
      

      그럼 tagNamenodeName의 차이는 없는 걸까요?

      물론 있습니다. 미묘하지만 이름에서 그 차이를 유추할 수 있죠.

      • tagName 프로퍼티는 요소 노드에만 존재합니다.
      • nodeName은 모든 Node에 있습니다.
        • 요소 노드를 대상으로 호출하면 tagName과 같은 역할을 합니다.
        • 텍스트 노드, 주석 노드 등에선 노드 타입을 나타내는 문자열을 반환합니다.

      nodeName은 모든 노드에서 지원되지만, tagNameElement 클래스로부터 유래되었기 때문에 요소 노드에서만 지원됩니다.

      document와 주석 노드를 사용해 tagNamenodeName의 차이점을 확인해 봅시다.

      <body><!-- 주석 -->
      
        <script>
          // 주석 노드를 대상으로 두 프로퍼티 비교
          alert( document.body.firstChild.tagName ); // undefined (요소가 아님)
          alert( document.body.firstChild.nodeName ); // #comment
      
          // 문서 노드를 대상으로 두 프로퍼티 비교
          alert( document.tagName ); // undefined (요소가 아님)
          alert( document.nodeName ); // #document
        </script>
      </body>
      

      요소 노드만 다루고 있다면 tagNamenodeName에는 차이가 없으므로 둘 다 사용할 수 있습니다.

  • innerHTML

    • innerHTML 프로퍼티를 사용하면 요소 안의 HTML을 문자열 형태로 받아올 수 있습니다.

      요소 안 HTML을 수정하는 것도 가능합니다. innerHTML은 페이지를 수정하는 데 쓰이는 강력한 방법의 하나입니다.

      document.body 안의 내용을 출력하고 완전히 바꾸는 예시를 살펴봅시다.

    • elem.innerHTML+="추가 html"을 사용하면 요소에 HTML을 추가할 수 있습니다.

      아래와 같이 말이죠.

      chatDiv.innerHTML += "<div>안녕하세요<img src='smile.gif'/> !</div>";
      chatDiv.innerHTML += "잘 지내죠?";
      

      그런데 ‘innerHTML+=’은 추가가 아니라 내용을 덮어쓰기 때문에 주의해서 사용해야 합니다.

      기술적으로 아래 두 줄의 코드는 동일한 역할을 합니다.

      elem.innerHTML += "...";
      // 위 코드는 아래 코드의 축약 버전입니다.
      elem.innerHTML = elem.innerHTML + "...";
      

      즉, innerHTML+=는 아래와 같은 일을 합니다.

      1. 기존 내용 삭제
      2. 기존 내용과 새로운 내용을 합친 새로운 내용을 씀
  • textContent

    • textContent를 사용하면 요소 내의 텍스트에 접근할 수 있습니다. <태그>는 제외하고 오로지 텍스트만 추출할 수 있죠.

      예시:

      <div id="news">
        <h1>주요 뉴스!</h1>
        <p>화성인이 지구를 침공하였습니다!</p>
      </div>
      
      <script>
        // 주요 뉴스! 화성인이 지구를 침공하였습니다!
        alert(news.textContent);
      </script>
      

      예시를 실행하면 원래부터 <태그>가 없었던 것처럼 텍스트만 반환되는 것을 확인할 수 있습니다.

      그런데 실무에선 텍스트 읽기를 단독으로 쓰는 경우는 흔치 않습니다.

      textContent를 사용하면 텍스트를 ‘안전한 방법’으로 쓸 수 있기 때문에 실무에선 textContent를 쓰기 용으로 유용하게 사용합니다.

      사용자가 입력한 임의의 문자열을 다시 출력해주는 경우를 생각해 봅시다.

      • innerHTML을 사용하면 사용자가 입력한 문자열이 ‘HTML 형태로’ 태그와 함께 저장됩니다.
      • textContent를 사용하면 사용자가 입력한 문자열이 ‘순수 텍스트 형태로’ 저장되기 때문에 태그를 구성하는 특수문자들이 문자열로 처리됩니다.

      두 프로퍼티를 비교해봅시다.

      <div id="elem1"></div>
      <div id="elem2"></div>
      
      <script>
        let name = prompt("이름을 알려주세요.", "<b>이보라</b>");
      
        elem1.innerHTML = name;
        elem2.textContent = name;
      </script>
      
      //이보라
      <b>이보라</b>
      
      1. 첫 번째 <div>엔 이름이 ‘HTML 형태’로 저장됩니다. 입력한 태그는 태그로 해석되어 굵은 글씨가 출력되네요.
      2. 두 번째 <div>엔 이름이 ‘텍스트 형태’로 저장됩니다. 따라서 입력한 값 그대로 <b>이보라</b>가 출력되는 것을 확인할 수 있습니다.

      개발을 하다보면 사용자의 입력값을 받아 처리해야 하는 경우가 많습니다. 이때 사용자가 입력한 값은 텍스트로 처리되어야 합니다. 예상치 못한 HTML이 사이트에 침투하는 것을 막으려면 textContent를 사용합시다.

📌 Window.prompt()

  • Window.prompt()는 사용자가 텍스트를 입력할 수 있도록 안내하는 선택적 메세지를 갖고 있는 대화 상자를 띄웁니다.
result = window.prompt(message, default);

  • hidden

    • hidden 속성과 hidden 프로퍼티는 요소를 보여줄지 말지 지정할 때 사용할 수 있습니다.

      hidden은 HTML 안에서 쓸 수도 있고 자바스크립트에서도 쓸 수 있습니다.

      <div>아래  div를 숨겨봅시다.</div>
      
      <div hidden>HTML의 hidden 속성 사용하기</div>
      
      <div id="elem">자바스크립트의 hidden 프로퍼티 사용하기</div>
      
      <script>
        elem.hidden = true;
      </script>
      
      // <div>아래 두 div를 숨겨봅시다.</div>
      
      

      hidden은 기술적으로 style="display:none"와 동일합니다. 짧다는 점만 다르죠.

      hidden을 사용해 요소를 깜빡이게 해봅시다.

      <div id="elem">깜빡이는 요소</div>
      
      <script>
        setInterval(() => elem.hidden = !elem.hidden, 1000);
      </script>
      

요약

  • 각 DOM 노드는 고유한 클래스에 속합니다. 클래스들은 계층 구조를 형성합니다. DOM 노드에서 지원하는 프로퍼티와 메서드는 계층 구조에서 어떤 클래스를 상속받느냐에 따라 결정됩니다.

    주요 DOM 노드 프로퍼티는 다음과 같습니다.

    • nodeType

      요소 타입을 알고 싶을 때 사용합니다. 요소 노드라면 1을, 텍스트 노드라면 3을 반환합니다. 두 타입 외에도 각 노드 타입엔 대응하는 상숫값이 있습니다. 읽기 전용입니다.

    • nodeName/tagName

      요소 노드의 태그 이름을 알아낼 때 사용합니다. XML 모드일 때를 제외하고 태그 이름은 항상 대문자로 변환됩니다. 요소 노드가 아닌 노드에는 nodeName을 사용하면 됩니다. 읽기 전용입니다.

    • innerHTML

      요소 안의 HTML을 알아낼 수 있습니다. 이 프로퍼티를 사용하면 요소 안의 HTML을 수정할 수도 있습니다.

    • outerHTML

      요소의 전체 HTML을 알아낼 수 있습니다. elem.outerHTML에 무언가를 할당해도 elem 자체는 바뀌지 않습니다. 대신 새로운 HTML이 외부 컨텍스트에서 만들어지고, elem이 삭제된 자리를 채웁니다.

    • nodeValue/data

      요소가 아닌 노드(텍스트, 주석 노드 등)의 내용을 읽을 때 쓰입니다. 두 프로퍼티는 거의 동일하게 동작합니다. 주로 data를 많이 사용하는 편이며 내용을 수정할 때도 이 프로퍼티를 쓸 수 있습니다.

    • textContent

      HTML에서 모든 <태그>를 제외한 텍스트만 읽을 때 사용합니다. 할당 연산을 통해 무언가를 쓸 수도 있는데 이때 태그를 포함한 모든 특수문자는 문자열로 처리됩니다. 사용자가 입력한 문자를 안전한 방법으로 처리하기 때문에 원치 않는 HTML이 사이트에 삽입되는 것을 예방할 수 있습니다.

    • hidden

      true로 설정하면 CSS에서 display:none을 설정한 것과 동일하게 동작합니다.

DOM 노드는 클래스에 따라 이 외에도 다른 프로퍼티를 가집니다. <input> 요소(HTMLInputElement)는 value, type 프로퍼티를, <a> 요소(HTMLAnchorElement)는 href 프로퍼티를 지원하는 것 같이 말이죠. 대부분의 표준 HTML 속성은 대응하는 DOM 프로퍼티를 가집니다.

그런데 HTML 요소와 DOM 프로퍼티가 항상 같은 것은 아닙니다. 관련 내용은 다음 챕터에서 살펴보도록 하겠습니다.

태그: ,

카테고리:

업데이트:

댓글남기기