【JavaScript】一旦初心に戻ってDOM操作を学び直す

##なぜ学び直すのかとその目的
学びの参考一覧
https://developer.mozilla.org/ja/docs/Web/API/NodeList
https://ginpen.com/2015/12/22/nodelist-vs-htmlcollection/
・書籍「JavaScript本格入門」p282~p293

`getElementById`とか、`querySelector`とかを使う簡単なDOM操作には結構慣れてきました。
でも、複数のDOM操作をする場合にあまり効率よくできてないんじゃないかな？
と思うことがあります。`item`やら`バブリング`やらを使いこなして、スッキリしたコードをかけるようになるべく再入門です。

##HTMLコレクション
DOMを取得するにあたって、複数のものを習得した場合の戻り値の１つが**HTMLCollection**です。

- getElementsByTagName
- getElementsByClassName
- getElementsByName

この辺の戻り値が`HTMLCollection`になっています。

```javascript:HTMLCollection取得

let myCollection = document.getElementsByTagName('meta');
console.log(myCollection);
```
こちらが結果になります。`HTMLCollection`というプロトタイプを継承しています。
![スクリーンショット 2019-08-13 9.09.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/b887707d-7432-a06b-c8ef-28cf91282cda.png)

こいつらをうまく扱うためには、まず道具を知るべしです。
以下が`HTMLCollecitonオブジェクト`のメンバーになります。

| メンバー | 概要 |
|:-:|:-:|
| length  | 要素数  |
| item(i)  | i番目の要素（0 ~ length-1の範囲)  |
|  namedItem(*name*) | id,またはname属性が一致する要素の取得  |


```javascript
let myCollection = document.getElementsByTagName('meta');
console.log(myCollection.item(2).content);
console.log(myCollection[2].content);
```
コードの2行目と3行目は同じ意味合いで、要は`item`はブラケット構文でも記述できる、ということです。

##もう１つのノードの集合体,NodeList

- Node.childNodes
- querySelectorAll

この辺の戻り値は`NodeList`と呼ばれるオブジェクトです。
`HTMLCollection`と利用できるメンバーもほぼ同じですが、異なる点もあります。
異なる点としては、

`HTMLCollection`は動的
`NodeList`は静的

ドユコトー？
だと思うので例を見てみましょう。

```HTML:HTML最初の状態
<div class="one"></div>
<div class="two"></div>
```

```javascript:javascriptでの操作
let myNodeList = document.querySelectorAll('div');  //ノードリスト
let myHTMLCollection = document.getElementsByClassName('bom'); //HTMLコレクション

let newNode = document.createElement('div'); 
newNode.classList.add('bom');
document.body.appendChild(newNode); //新しく<div class="bom"></div>を追加する

console.log(myNodeList.length); //戻り値 2
console.log(myHTMLCollection.length); //戻り値 3
```

`NodeList`は静的なので、取得後DOMの操作があってもそれが反映されていません。
対して`HTMLCollection`は取得後のDOM操作も感知していて動的です。

##ノードウォーキングについて
document.xxxxxっていう要素の取得って...
**毎回毎回documentから辿ってってるわけじゃないですか。**
例えば３階にある電気屋の炊飯器と冷蔵庫を見にきたのに、
「ここが3階で...あ、炊飯器だ！　よし、また一階に戻って冷蔵庫を探そう！」
っていうのと同じでかなり無駄ですね。

そこで特定のノードを基点に相対的な位置関係からノード取得をする方法が役に立ちます。
**ノードウォーキング**と呼ばれています。

基点のノードをgetXXXX/queryXXXX　系で取得して、そこからノードウォーキングしていけば良さげです。

```HTML:HTML
<body>
    <form>
        <label for="animal">動物を選んでね</label>
        <select id="animal">
            <option value="犬">犬</option>
            <option value="ネコ">ネコ</option>
            <option value="コモドオオトカゲ">コモドオオトカゲ</option>
        </select>
    </form>
</body>
```

```javascript:子要素以下の取得
let basePoint = document.getElementById('animal');
let opts = basePoint.childNodes;  //ここに子要素以下が格納される
```

ただ注意しなければいけないのが、`childNodes`プロパティが取得するノードはNodeListである点と、ノードが**要素ノードだけでない**
という点です。空白ノードやテキストノードを含んでしまっています。
詳しくは下記のリンク等を参考にしてください。
https://www.javadrive.jp/javascript/dom/index4.html

以下、`console.log(basePoint.childNodes)`の結果です。

![スクリーンショット 2019-08-13 10.21.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/da21067b-c84a-a285-08d4-c611e76b0760.png)


そこでnodeの種類を判別しなければなりませんね。
`nodeTypeプロパティ`を使用すればそれができます！
nodeTypeで判別できるノードの種類はかなりのものがあるんですが、以下を抑えておけば実務では使えそうです。

| 戻り値 | ノードの種類 |
|:-:|:-:|
| 1  | 要素ノード  |
| 2  |  属性ノード |
| 3 | テキストノード  |

以上を踏まえて、上記のHTMLのoptionを取得してみます。

```javascript:ノードウォーキングによる要素取得
let basePoint = document.getElementById('animal');
let opts = basePoint.childNodes; //ノードウォーキングの基点

for(let i = 0;i < opts.length; i++){ //取得した全てのノードをチェック
    if(opts[i].nodeType === 1){  //要素ノードなら
        console.log(opts[i].value);   //valueを出力
    }
}
```

##子要素リストのその他の取得方法

```javascript:その他の子要素取得方法
let child = baseNode.firstElementChild
while(child){
   console.log(child.value);
   child.nextElementSibling;  //兄弟要素取得
}
```

`firstElementChild`・・・要素直下の最初の子要素を取得
`nextElementSibling`・・・要素の次の兄弟要素を取得

どちらも要素エレメントしか取得しないので、`nodeType`判定が不要な分スッキリしています。
このコードは子要素の兄弟エレメントがなくなるまでループをかけることで、子要素全てを取得していますね。

##感想
とりあえず取得できればOK!で今までコーディングしてきたので、
ノードウォーキングはあまり意識していませんでした。今後の役に立ちそうです。
次回はイベント系の処理をしっかり学び直します！