作者:簡生
鏈接:https://www.zhihu.com/question/24702250/answer/28695133
來源:知乎
1. W3C 標准
querySelectorAll 屬於 W3C 中的 Selectors API 規范 [1]。而 getElementsBy 系列則屬於 W3C 的 DOM 規范 [2]。
2. 瀏覽器兼容
querySelectorAll 已被 IE 8+、FF 3.5+、Safari 3.1+、Chrome 和 Opera 10+ 良好支持 。
getElementsBy 系列,以最遲添加到規范中的 getElementsByClassName 為例,IE 9+、FF 3 +、Safari 3.1+、Chrome 和 Opera 9+ 都已經支持該方法了。
3. 接收參數
querySelectorAll 方法接收的參數是一個 CSS 選擇符。而 getElementsBy 系列接收的參數只能是單一的className、tagName 和 name。代碼如下 [3]:
varc1=document.querySelectorAll('.b1 .c');varc2=document.getElementsByClassName('c');varc3=document.getElementsByClassName('b2')[0].getElementsByClassName('c');
需要注意的是,querySelectorAll 所接收的參數是必須嚴格符合 CSS 選擇符規范的。所以下面這種寫法,將會拋出異常。代碼如下 [4]:
try{vare1=document.getElementsByClassName('1a2b3c');vare2=document.querySelectorAll('.1a2b3c');}catch(e){console.error(e.message);}console.log(e1&&e1[0].className);console.log(e2&&e2[0].className);
(CSS 選擇器中的元素名,類和 ID 均不能以數字為開頭。)
4. 返回值
大部分人都知道,querySelectorAll 返回的是一個 Static Node List,而 getElementsBy 系列的返回的是一個 Live Node List。
看看下面這個經典的例子 [5]:
// Demo 1varul=document.querySelectorAll('ul')[0],lis=ul.querySelectorAll("li");for(vari=0;i
因為 Demo 2 中的 lis 是一個動態的 Node List, 每一次調用 lis 都會重新對文檔進行查詢,導致無限循環的問題。
而 Demo 1 中的 lis 是一個靜態的 Node List,是一個 li 集合的快照,對文檔的任何操作都不會對其產生影響。
但為什么要這樣設計呢?
其實,在 W3C 規范中對 querySelectorAll 方法有明確規定 [6]:
The NodeList object returned by the querySelectorAll() methodmust be static([DOM], section 8).
那什么是 NodeList 呢?
W3C 中是這樣說明的 [7]:
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.
所以,NodeList 本質上是一個動態的 Node 集合,只是規范中對 querySelectorAll 有明確要求,規定其必須返回一個靜態的 NodeList 對象。
我們再看看在 Chrome 上面是個什么樣的情況:
document.querySelectorAll('a').toString();// return "[object NodeList]"document.getElementsByTagName('a').toString();// return "[object HTMLCollection]"
這里又多了一個 HTMLCollection 對象出來,那 HTMLCollection 又是什么?
HTMLCollection 在 W3C 的定義如下 [8]:
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.
實際上,HTMLCollection 和 NodeList 十分相似,都是一個動態的元素集合,每次訪問都需要重新對文檔進行查詢。兩者的本質上差別在於,HTMLCollection 是屬於Document Object Model HTML規范,而 NodeList 屬於Document Object Model Core規范。
這樣說有點難理解,看看下面的例子會比較好理解 [9]:
varul=document.getElementsByTagName('ul')[0],lis1=ul.childNodes,lis2=ul.children;console.log(lis1.toString(),lis1.length);// "[object NodeList]" 11console.log(lis2.toString(),lis2.length);// "[object HTMLCollection]" 4
NodeList 對象會包含文檔中的所有節點,如 Element、Text 和 Comment 等。
HTMLCollection 對象只會包含文檔中的 Element 節點。
另外,HTMLCollection 對象比 NodeList 對象 多提供了一個 namedItem 方法。
所以在現代瀏覽器中,querySelectorAll 的返回值是一個靜態的 NodeList 對象,而 getElementsBy 系列的返回值實際上是一個 HTMLCollection 對象 。