# Do You Know The Difference? (HTML Collection、NodeList)
:::success
:bookmark: 書籤
[TOC]
:::
## HTMLCollection & NodeList
當我們使用DOM提供的方法來獲取節點時,會根據語法的使用返回不同型態的資料。
直接來看範例
***index.html***
```htmlembedded=
<div class="boxParent">
<p>Hello World</p>
<div class="box">
<p>123</p>
<span>456</span>
789
</div>
</div>
```
***app.js***
```javascript=
const box = document.querySelector(".box");
console.log(box.parentElement) // output: div.boxParent
console.log(box.parentNode) // output: div.boxParent
```
使用parentElement和parentNode返回的資料型態都是一樣的
那如果是用children和childNodes呢?
***app.js***
```javascript=
const box = document.querySelector(".box");
console.log(box.children);
/*
* output :
* 0 : p
* 1 : span
* length : 2
* [[Prototype]] : HTMLCollection
* */
console.log(box.childNodes);
/*
* output :
* 0 : text
* 1 : p
* 2 : text
* 3 : span
* 4 : text
* length : 5
* [[Prototype]] : NodeList
* */
```
可以發現返回的分別是HTMLCollection 和 NodeList 型態,而這兩個有什麼差別呢?
我們可以展開Prototype看裡面提供的methods

這邊可以注意到,我們常用的陣列方法並沒有出現在裡面,像是map、filter等,
但NodeList有提供forEach方法而HTMLCollection則是沒有。
而要怎麼讓這些型態擁有map和filter方法呢?
很簡單,直接看以下程式碼:
***app.js***
```javascript=
const box = document.querySelector(".box");
console.log(Array.from(box.parentElement) // 直接轉成陣列
console.log(Array.from(box.parentNode)) // 直接轉成陣列
```
使用 **Array.from()** 後,可以看到Prototype如下:


## getElementByClassName ?
現在我們使用DOM方法時,比較少用到getElement的方法,因為有querySelector和querySelectorAll可以使用,但有沒有好奇過getElement的方法和querySelector差在哪?
getElement系列,只要是能夠返回多個元素(節點)的都會是HTMLCollection型態,這與NodeList差在哪裡? 直接來看以下程式碼:
我們把index.html改成以下
***index.html***
```htmlembedded=
<div class="boxParent">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
```
***app.js***
```javascript=
const boxes = document.getElementsByClassName("box");
console.log(boxes);
/**
* output :
* 0 : div.box
* 1 : div.box
* 2 : div.box
* length : 3
* [[Prototype]] : HTMLCollection
* /
```
可以看到返回的是HTMLCollection型態,還沒結束~ 我們接著看!
***app.js***
```javascript=
const boxes = document.getElementsByClassName("box");
console.log(boxes);
const boxParent = document.querySelector(".boxParent");
const box = document.createElement("div");
box.classList.add("box");
boxParent.appendChild(box);
console.log(boxes);
```
以上的程式碼,輸出的結果會是....

可以看到HTMLCollection有 **即時更新(Live Updates)** 的特性。
現在換成我們常用的querySelectorAll!
***app.js***
```javascript=
const boxes = document.querySelectorAll(".box");
console.log(boxes);
const boxParent = document.querySelector(".boxParent");
const box = document.createElement("div");
box.classList.add("box");
boxParent.appendChild(box);
console.log(boxes);
```
結果如下:

可以看到NodeList沒有 **即時更新(Live Updates)** 的特性。
## 延伸
在我們使用childNodes的時候,有沒有發現底下的元素(節點)只有兩個,但返回的資料長度是五個!

這是因為文字也被當作是節點,所以我們程式碼裡面的文字789也算是一個。
但這樣加起來也才三個,那剩下的兩個是哪來的?
答案是換行! 我們實際展開來看就知道了~

\n 就是換行的意思,所以如果要只抓元素(節點)來使用的話,建議使用children然後用Array.from()轉型態就好了。
