HTMLCollection 和 Nodelist 的異同?

HTMLCollection 和 Nodelist 的異同?

1. w3 關於這兩者的定義

HTMLCollection: An HTMLCollection is a list of nodes. An individual node may be accessed by either ordinal index or the node's name or id attributes. Note: Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed.

NodeList: The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.

The items in the NodeList are accessible via an integral index, starting from 0.

HTMLCollectionNodeList 都是元素節點的集合, 前者可以按照索引/節點name/節點id 屬性訪問。 後者可以按照索引訪問。

1.1 實例屬性

HTMLCollectionNodeList 都只有一個實例屬性:

  • length: 返回節點集合的長度

1.2 實例方法

HTMLCollection NodeList
HTMLCollection.item()
傳入元素 index 返回特定的節點
NodeList.item()
傳入索引返回特定節點
HTMLCollection.namedItem()
傳入節點的 name 屬性,返回特定的節點
NodeList.entries()
返回key-value 的迭代器
⚠️HTMLCollection 沒有 forEach 方法 NodeList.forEach()
節點遍歷方法
NodeList.keys()
返回NodeList 的所有key值的迭代器,這裏也就是索引
NodeList.values()
返回NodeList 的所有value值的迭代器,也就四節點本身

一些示例:

  <body>
    <p name="p1" class="para">Lorem, ipsum dolor.</p>
    <p name="p2" class="para">Lorem ipsum dolor sit amet.</p>
    <p name="p3" class="para">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  </body>
  <script>
    const paras = document.getElementsByClassName('para');
    console.log(paras.item(0).innerHTML);//Lorem, ipsum dolor.
    console.log(paras.namedItem('p3').innerHTML);//Lorem ipsum dolor sit amet, consectetur adipisicing elit.
  </script>
  <body>
    <p name="p1" class="para">Lorem, ipsum dolor.</p>
    <p name="p2" class="para">Lorem ipsum dolor sit amet.</p>
    <p name="p3" class="para">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  </body>
  <script>
    const paras = document.querySelectorAll('.para');
    console.log('log1:', paras.item(0).innerHTML);
    console.log('log2:', paras.entries());
    console.log('log3:', paras.entries().next());
    console.log('log4:', paras.keys());
    console.log('log5:', paras.keys().next());
    console.log('log6:', paras.values());
    console.log('log7:', paras.values().next());
    paras.forEach((p) => {
      console.log('[p.innerHTML]: ', p.innerHTML);
    });
  </script>

image

特別說明,在實例方法中, NodeList/HTMLCollection.item()方法僅接受索引值。

2. 哪些常見操作會返回這二者?

HTMLCollection

  • document.getElementsByTagName

  • document.getElementsByClassName

  • HTMLElement.children

  • document.forms

  • document.images

NodeList:

  • document.getElementsByName
  • document.querySelectorAll
  • HTMLElement.childNodes

3. 二者有什麼相同點?

二者所包含的結點都是響應式的,也就是說,當所依賴的文檔發生了變化,相應的DOM視圖也會發生更新。

NodeList

爲了驗證這一點,我們可以使用 Array.from(淺拷貝來測試一下):

  <script>
    const paras = document.querySelectorAll('.para');
    const copy = Array.from(paras);
    copy.forEach((cp) => {
      cp.innerHTML += new Date().toLocaleTimeString();
    });
    paras.forEach((p) => {
      console.log('[p.innerHTML]: ', p.innerHTML);
    });
      //[p.innerHTML]:  Lorem, ipsum dolor.9:42:54 AM
      //[p.innerHTML]:  Lorem ipsum dolor sit amet.9:42:54 AM
      //[p.innerHTML]:  Lorem ipsum dolor sit amet, consectetur adipisicing 
  </script>

image

說明拷貝對象中的DOM 元素髮生了變化,視圖會發生更新。

HTMLCollection

對於 HTMLCollection 也是這樣的,

  <script>
    const paras = document.getElementsByClassName('para');
    const copy = Array.from(paras);
    copy.forEach((cp) => {
      cp.innerHTML += new Date().toLocaleTimeString();
    });
    [...paras].forEach((p) => {
      console.log('[p.innerHTML]: ', p.innerHTML);
    });
      //[p.innerHTML]:  Lorem, ipsum dolor.9:42:54 AM
      //[p.innerHTML]:  Lorem ipsum dolor sit amet.9:42:54 AM
      //[p.innerHTML]:  Lorem ipsum dolor sit amet, consectetur adipisicing elit.9:42:54 AM
  </script>

需要注意的是,這裏HTMLCollection 類數組是沒有forEach 方法的, 所有我們用擴展元算符(其實也是淺拷貝)將其轉換成了一個數組。

4. 二者有什麼區別?

最重要的區別是, HTMLCollection 僅包含 tags(以及id/name分別標記的) 元素, 而 NodeList 包含所有的節點。 例如:

  • 元素節點

  • 屬性節點

  • 文本節點(空白字符也會被視作文本節點)

  • 註釋節點

    node types

示例:

  <body>
    <ul id="myList">
      <!-- List items -->
      <li name="li-name-01" id="li-id-01">List item 1</li>
      <li name="li-name-02" id="li-id-02">List item 2</li>
      <li name="li-name-03" id="li-id-03">List item 3</li>
      <li name="li-name-04" id="li-id-04">List item 4</li>
      <li name="li-name-05" id="li-id-05">List item 5</li>
    </ul>
  </body>
  <script>
    const ul = document.getElementById('myList');
    console.log('[ul.children]: ', ul.children);
    console.log('[ul.childNodes]: ', ul.childNodes);
  </script>

image

這意味着,對於有id節點的 HTMLCollection 返回類型, 你可以這樣去訪問:

console.log('[li[0]]: ', li[0]); //li#li-01
console.log("[li['li-01']]: ", li['li-01']);//li#li-01

並且這二者完全一樣:

console.log(li[0] === li['li-01']);//true

name 也是如此

另外,儘管如此,HTMLCollection/NodeList 的 item 方法依舊僅能通過索引訪問,而不能夠通過id/name 訪問。

const li = document.getElementsByTagName('li');
const _li = document.querySelectorAll('li');

//以下打印: li#li-03
console.log('[li.item(2)]: ', li.item(2));
console.log('[_li.item(2)]: ', _li.item(2));

//以下打印: li#li-01
console.log('[li.item("")]: ', li.item(''));
console.log('[li.item("li-03")]: ', li.item('li-03'));
console.log('[_li.item("")]: ', _li.item(''));
console.log('[_li.item("li-03")]: ', _li.item('li-03'));

即item參數如果接收一個非數值參數,將默認返回第一個元素,如果沒有元素,那麼返回 null!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章