Array,NodeList, HTMLCollection這三個概念和它們之間的關係有不少作了幾年前端的同窗都搞不清楚,常常遇到可是又感受很陌生,剪不斷理還亂的感受。今天我們就來理清這三個東西。html
對於Array你們差很少都能弄明白,可是HTMLCollectio、NodeList和Array的關係好像老是很曖昧,有一點像可是又不那麼像,多是我比較笨,可是真的被它們弄得很頭疼啊,因此今天下決心必須弄懂它們。前端
我們先無論那麼多概念和定義,先來看看這三個東西到底長什麼樣。我們先建立一個html文件,裏面就放三個嵌套的div:node
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div class="test-div"> div1 <div class="test-div"> div2 <div class="test-div"> div3 </div> </div> </div> </body> </html>
首先讓咱們來研究一下NodeList,在瀏覽器中打開這個html文件,打開控制檯輸入:數組
document.querySelectorAll('div')
咱們發現返回的NodeList中包含這三個div。展開NodeList的__proto__
屬性後發現,NodeList繼承於一個NodeList對象,而這個NodeList對象又繼承於Object對象。瀏覽器
NodeList除了length
屬性外還有其餘5個方法(method),分別是entries, forEach, item, keys, values
,這五個方法都是幹什麼用的呢?用一遍就知道:ui
調用entries方法會返回一個iterator(迭代器),關於iterator/iterable能夠參見MDN,簡單點說就是返回了一個能夠遍歷的對象,而這個對象實現了iterable protocal,因此須要用for...of
遍歷,因此咱們能夠:this
var divs = document.querySelectorAll('div'); for(var item of divs.entries()){ console.log(item); }
結果返回了三個包含三個div對象數組(爲何不是三個key-value pair?),如圖:spa
forEach的用法和Array的forEach用法同樣,都是用於遍歷集合元素:翻譯
var divs = document.querySelectorAll('div'); divs.forEach(function (el, index, list) { console.log(el); });
item()
用於從NodeList中獲取單個節點元素:3d
var divs = document.querySelectorAll('div'); console.log(divs.item(0));
打印結果:
返回一個iterator用於遍歷NodeList的key:
var divs = document.querySelectorAll('div'); for (var key of list.keys()) { console.log(key); }
打印結果:
和keys()
相似,返回一個iterator用於遍歷NodeList的value,即html元素:
var divs = document.querySelectorAll('div'); for (var value of divs.values()) { console.log(value); }
打印結果:
經過對NodeList的研究咱們發現,NodeList和Array沒有繼承關係,可是都有length
屬性和forEach
方法,並且擁有幾個特有的方法,主要都是用來遍歷和取值用的。
認識了NodeList,咱們再來認識一下HTMLCollection,一樣咱們先獲取到一個HTMLCollection,在控制檯中輸入並執行:
document.getElementsByTagName('div')
打印結果:
能夠看到獲得的HTMLCollection繼承於一個HTMLCollection對象,而HTMLCollection又直接繼承於Object對象,因此它和NodeList是平級的。HTMLCollection和NodeList同樣包含了查詢獲得的html元素,length
屬性和item
方法,但沒有NodeList的entries, forEach, keys, values
這四個方法,可是又多了一個namedItem
(根據id和name篩選元素)方法...
看到了NodeList和HTMLCollection這兩個傢伙的真容,咱們很好奇這兩個有不少類似又相互獨立的傢伙是怎麼被髮明出來的呢?什麼狀況下獲得的是NodeList,什麼狀況是HTMLCollection呢?
MDN上是這麼介紹HTMLCollection的:
Note: This interface is called HTMLCollection for historical reasons (before the modern DOM, collections implementing this interface could only have HTML elements as their items).
翻譯一下就是:
之因此叫它HTMLCollection是由於某些歷史緣由,在新一代DOM出現以前,實現HTMLCollection這個接口的集合只包含HTML元素,因此命名爲HTMLCollection。
咱們知道DOM節點(node)不光包含HTML元素,還包含text node(字符節點)和comment(註釋),既然HTMLCollection只包含HTML元素,那NodeList是否是會包含全部類型的DOM節點呢,咱們來試驗一下,先寫一段html:
<div class="parent"> this is patent content <div class="child"> this is child content </div> <!-- this is comment --> </div>
而後執行:
var parent = document.querySelector('.parent'); console.log(parent.childNodes);
打印結果:
咱們看到childNodes
返回的是第一個div下面的全部DOM節點,包含3個text node(其中兩個是換行符),一個子div,一個comment。這證明了咱們對NodeList的猜測。
咱們再看一下HTMLCollection,執行:
var parent = document.querySelector('.parent'); console.log(parent.children);
打印結果:
只包含了子div,也驗證了MDN上的說法。
至於parent即有childNodes屬性,又有children屬性呢?
由於parent便是一個Node對象(擁有childNodes屬性),又由於它有子元素因此它又是一個ParentNode對象(擁有children屬性)。
至此,咱們對NodeList和HTMLCollection應該有一個比較全面的認識,總結一下就是HTMLCollection是比較早期的模型,只能包含HTML元素,早期就有的接口如document.getElementsByClassName
, document.getElementsByTagName
返回的就是HTMLCollection。NodeList是比較新的模型,相比HTMLCollection更加完善,不光有HTML元素,還有text節點和comment。比較新的接口如document.querySelectorAll
返回的就是NodeList。
關於NodeList,HTMLCollection和Array的關係,就是長得像,有個別類似的功能,可是是徹底不同的東西。
固然關於HTMLCollection和NodeList的故事尚未講完,由於它們有時候是live(活的?動態的?),有時候是not live(死的?靜態的?),關於這個話題,以後的文章再詳細分析。