昨天看到一個querySelectorAll()的東西,發現用法跟getElementsBy系列類似,便想深究一下它們之間的不同點,以下為找到的資料。
ps:瞭解這個知識點的原因
前兩天我在重溫js dom編程的時候,看到了擷取dom元素這一章,然後看到了getElementsByTagName()和getElementsByClassName(),之後又瞭解到了現代瀏覽器新出的一個DOM API–querySelectorAll().以我的性格,看到這些方法之後我肯定是想瞭解一下它們的不同點啦,所以我就翻閱資料,就看到了stackoverflow上面的一個問題
var temp = document.querySelectorAll(".class");for (var i=0, max=temp.length; i<max; i++) { temp[i].className = "new_class";}var temp = document.getElementsByClassName("class");for (var i=0, max=temp.length; i<max; i++) { temp[i].className = "new_class";}
運行上述這兩段代碼,假如擷取到的temp的長度都為3,那麼第一段代碼能將三個元素的className全部更改為new_class",而第二段代碼只能講第一個元素和第三個元素的className更改為"new_class".這裡面的原因就是動態nodelist和靜態nodelist的區別。 然後我又翻閱資料尋找什麼是動態nodelist,什麼是靜態nodelist。於是乎,就有了下面的長篇大論。 說說NodeList,HTMLCollection以及NamedNodeMap
在不同版本的瀏覽器中,如果調用擷取多元素的DOM方法(getElement…()),有的會得到NodeList(多為舊瀏覽器),有的會得到HTMLCollection(多為新瀏覽器)。使用Node Interface的方法,如childNodes,得到的通常是NodeList,而使用其他Interface的方法,又有可能得到HTMLCollection。而NamedNodeMap又和前面兩者返回的東西類型也不相同,所以有必要瞭解一下這三者的區別。
1. 三者的相同點
1.1 三者都具有length屬性
1.2 三者都有item()方法
1.3 三個集合都是”動態”,如果對NodeList和HTMLCollection中的元素進行操作都會直接反映到DOM中,因此如果一次性直接在集合中進行DOM操作的話,開銷非常大。(這會在講解動態時候詳細解釋)
2. 三者的不同點
2.1 nodeList裡麵包含了所有的節點類型,比如元素節點,文本節點等
2.2 HTMLCollection裡面只包含元素節點
<div> <!-- Comment --> <p>This is Some Text</p></div>
上面這段代碼,如果作為NodeList返回,那麼瀏覽器最多會給這個列表5個元素
1.一個<div>和注釋間的斷行和空格(或tab)作為text node(沒錯,標籤之間的空白符號也可以被解析為text node
2.注釋作為comment node
3.注釋和<p>之間的斷行和空格(或tab)作為text node,p作為element
4.</p>和</div>之間的斷行和空格(或tab)作為text node
但是如果是作為HTMLCollection返回的話,那麼就一個<p>元素這麼簡單
2.3 NamedNodeMap裡麵包含了”Attribute”的集合,例如id,title,name等,集合中的每一個元素都是attr類型。
2.4 三個集合所提供的方法也不相同,例如HTMLCollection中提供了namedItem(),而其它兩個集合就沒有提供這個方法
擴充點:
item和namedItem都可以通過[]的縮寫進行調用,有的瀏覽器還支援用()的縮寫進行調用(也就是可以list[index],list[key]或者list(index),list(key)),以及直接用dot notation調用namedItem(比如list.key)
IE8及以下版本瀏覽器中,注釋屬於HTMLCommentElement,算作Element,因此會出現在HTMLCollection裡
我們可以用alert/console.log(document.getElement…)列印出來看下返回的是什麼類型的集合,下面這個連結中講的也算詳細,可以參考下:http://www.jb51.net/article/25747.htm
ps:以上知識點參考連結:
http://www.cnblogs.com/joyeecheung/p/4067927.html,http://stackoverflow.com/questions/15763358/difference-between-htmlcollection-nodelists-and-arrays-of-objects, http://stackoverflow.com/questions/26047844/getelementsbyclassname-vs-queryselectorall 說了這麼多,那麼到底什麼是動態NodeList?什麼是靜態NodeList呢。它們之間有什麼區別。 動態NodeList
上面我們說到NodeList,HTMLCollection以及NamedNodeMap都是動態。也就是說,對底層文檔結構的修改會動態地反映到相關的結合NodeList,HTMLCollection以及NamedNodeMap中。例如:如果先擷取了某個元素的子項目的動態集合NodeList對象,然後又在其他地方對這個元素進行操作(添加,修改,刪除子項目等操作),這些更改將自動反射到NodeList中,不需要手動進行操作。
因為getElementsByTagName(所有getElement…方法都會返回動態NodeList)方法返回的是一個動態集合,所以只要document發生變化,就會自動更新對應的元素。因此,下面的代碼是一個死迴圈:
var divs = document.getElementsByTagName("div");var i=0;while(i < divs.length){ document.body.appendChild(document.createElement("div")); i++;}
死迴圈的原因是每次迴圈都會重新計算divs.length.每次迭代都會添加一個新的<div>,所以每次i++,對應的divs.length也在增加,所以i永遠比divs.length小,迴圈終止條件也就永遠不會觸發。
解決上述代碼死迴圈的辦法可以是用一個變數儲存divs.length或者改用querySelectorAll():
var divs = document.getElementsByTagName("div");var i=0,len = divs.length;while(i < len){ document.body.appendChild(document.createElement("div")); i++;}
你可能會覺得這種動態集合是個壞主意, 但通過動態集合可以保證某些使用非常普遍的對象在各種情況下都是同一個,而且動態NodeList比靜態NodeList快很多很多(下面解釋原因) 靜態NodeList
querySelectorAll()和querySelector()方法返回的是一個靜態NodeList,所謂靜態NodeList就是對底層document的更改不會影響到返回的這個NodeList對象.此時返回的NodeList只是querySelectorAll()方法被調用時的文檔狀態的快照。所以下面的代碼不會是死迴圈:
var divs = document.querySelectorAll("div");var i=0;while(i < divs.length){ document.body.appendChild(document