JavaScriptでDOMツリーを表示してNode,Elementを理解する

# はじめに
`CSS`や`HTML`の勉強をしていると、よく`Node`、`Element`という言葉が出てくるのですがいまいち理解できなかったので、整理してみました。  

# 結論
適当なhtmlを作成して、それのDOMツリー(もどき)を見て理解するのが一番分かりやすかったです。
```javascript:sample.js
//ページ読み込み時にDOMツリー(もどき)を表示
window.addEventListener("DOMContentLoaded", () => {

    //すべてのNodeを表示
    let domTreeView = (i, node) => {
        //Nodeタイプ番号
        let types = [
            "",//0
            "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非推奨
        ];

        //自分自身
        console.log(
            String(i).padStart(i + 1, " "),//階層
            node,//Node
            node.nodeType,//Nodeタイプ番号
            types[node.nodeType]//Nodeタイプ文字列
        );

        //NodeがElementの場合はAttributeNodeも表示  
        if (node.nodeType == Node.ELEMENT_NODE) {
            node.getAttributeNames().forEach(name => {
                let attr = node.getAttributeNode(name);
                console.log(
                    "-> attr".padStart(i + 2 + "-> attr".length, " "),//階層
                    attr,//Node
                    attr.nodeType,//Nodeタイプ番号
                    types[attr.nodeType]//Nodeタイプ文字列
                );
            });
        }

        //すべての子Nodeについて処理
        node.childNodes.forEach(child => {
            //Nodeを再帰的に表示
            domTreeView(i + 1, child);
        });
    };

    //documentのNodeを表示
    domTreeView(0, document);
});
```
適当なhtmlを作成して、
```html:sample.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <script src="sample.js"></script>
</head>

<body>
    <div id="box">Hello</div>
    <!-- コメント -->
</body>

</html>
```
ブラウザで表示させたときの結果  
![domtree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/8d27728d-b2ce-c5db-9d6b-6947e7162483.png)  

`document`自身は`Documentノード`であり、直下（先頭に1と表示されているもの）に2つの`Node`があります。  

* 1つの`DocumentTypeノード` （`<!DOCTYPE html>`のこと）  
* 1つの`Elementノード` （`<html>...</html>`のこと）  

つまり直下の`Elementノード`としては`<html>...</html>`の1つのみです。また`<html>...</html>`の中には、更に複数の`Node`が階層的に存在します。  

* `Elementノード`  &lt;head&gt;要素、&lt;body&gt;要素、&lt;div&gt;要素など  
* `Textノード` Helloだけでなく改行やスペースも含む  
* `Commentノード` &lt;!--  コメント  --&gt;

以下に示すように`Element`はあくまで`Node`を継承しているものの1つにすぎないということです。

# 継承関係

```mermaid
graph RL
  Node-->EventTarget["EventTarget"]:::normalclass
  Documment["Documment (9)"]:::nodelclass-->Node:::parentclass
  DocumentFragment["DocumentFragment (11)"]:::nodelclass-->Node
  DocumentType["DocumentType (10)"]:::nodelclass-->Node
  Element["Element (1)"]:::nodelclass-->Node
  HTMLElement:::normalclass-->Element
  Attr["Attr (2)"]:::nodelclass-->Node
  CharacterData-->Node
  Text["Text (3)"]:::nodelclass-->CharacterData:::normalclass
  CDATASection["CDATASection (4)"]:::nodelclass-->Text
  Comment["Comment (8)"]:::nodelclass-->CharacterData
  ProcessingInstruction["ProcessingInstruction (7)"]:::nodelclass-->CharacterData

  
  classDef normalclass fill:#fff,stroke:#000
  classDef nodelclass fill:#fdffd3,stroke:#000
  classDef parentclass fill:#d9ffd3,stroke:#000

  click EventTarget "https://developer.mozilla.org/ja/docs/Web/API/EventTarget"
  click Node "https://developer.mozilla.org/ja/docs/Web/API/Node"
  click Documment "https://developer.mozilla.org/ja/docs/Web/API/Document"
  click DocumentFragment "https://developer.mozilla.org/ja/docs/Web/API/DocumentFragment"
  click DocumentType "https://developer.mozilla.org/ja/docs/Web/API/DocumentType"
  click Element "https://developer.mozilla.org/ja/docs/Web/API/Element"
  click Attr "https://developer.mozilla.org/ja/docs/Web/API/Attr"
  click Text "https://developer.mozilla.org/ja/docs/Web/API/Text"
  click CDATASection "https://developer.mozilla.org/ja/docs/Web/API/CDATASection"
  click Comment "https://developer.mozilla.org/ja/docs/Web/API/Comment"
  click ProcessingInstruction "https://developer.mozilla.org/ja/docs/Web/API/ProcessingInstruction"
  click CharacterData "https://developer.mozilla.org/ja/docs/Web/API/CharacterData"
  click HTMLElement "https://developer.mozilla.org/ja/docs/Web/API/HTMLElement"

```
|ノードの種類|例|nodeTypeの名前|数値|
|:----|:----|:----|:----|
|Element|&lt;div&gt;など|ELEMENT_NODE|1|
|Attribute| |ATTRIBUTE_NODE|2|
|Text|&lt;div&gt;Hello&lt;/div&gt;のHelloやhtml内の1行ごとの改行など|TEXT_NODE|3|
|CDATASection|&lt;!CDATA[[ &hellip; ]]&gt;|CDATA_SECTION_NODE|4|
|ProcessingInstruction|&lt;?xml-stylesheet &hellip; ?&gt;|PROCESSING_INSTRUCTION_NODE|7|
|Comment|&lt;!--  --&gt;|COMMENT_NODE|8|
|Document| |DOCUMENT_NODE|9|
|DocumentType|&lt;!DOCTYPE html&gt;|DOCUMENT_TYPE_NODE|10|
|DocumentFragment | |DOCUMENT_FRAGMENT_NODE|11|

# 参考URL
* [Node - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Node)  
* [Element - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Element)  
* [Document - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Document)  
* [HTMLElement - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement)  
* [DOM の紹介 - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/Introduction)  
* [W3C DOM Level 1 Core の使用 - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Document_object_model/Using_the_Document_Object_Model)  
* [ホワイトスペースは HTML、 CSS、そして DOM 内でどう扱われるか - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/Whitespace)  
* [Element (要素) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN](https://developer.mozilla.org/ja/docs/Glossary/Element)  
* [【Mermaidの紹介】Qiitaでダイアグラム・チャートが簡単に書けるようになりました！ - Qiita](https://qiita.com/Qiita/items/c07f3262d8f3b25f06c9)