querySelectorAll 方法和 getElementsBy 系列方法的區別

 

本文是我在知乎上的一個回答:http://www.zhihu.com/question/24702250/answer/28695133html

 

 

————— 下面是正文 —————node

 

1. W3C 標準
querySelectorAll 屬於 W3C 中的 Selectors API 規範 [1]。而 getElementsBy 系列則屬於 W3C 的 DOM 規範 [2]。api

 

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]:app

var c1 = document.querySelectorAll('.b1 .c');
var c2 = document.getElementsByClassName('c');
var c3 = document.getElementsByClassName('b2')[0].getElementsByClassName('c');

須要注意的是,querySelectorAll 所接收的參數是必須嚴格符合 CSS 選擇符規範的。因此下面這種寫法,將會拋出異常。代碼以下 [4]:ide

try {
  var e1 = document.getElementsByClassName('1a2b3c');
  var e2 = document.querySelectorAll('.1a2b3c');
} catch (e) {
  console.error(e.message);
}
console.log(e1 && e1[0].className);
console.log(e2 && e2[0].className);

(CSS 選擇器中的元素名,類和 ID 均不能以數字爲開頭。)this

 

4. 返回值
大部分人都知道,querySelectorAll 返回的是一個 Static Node List,而 getElementsBy 系列的返回的是一個 Live Node List。
看看下面這個經典的例子 [5]:spa

// Demo 1
var ul = document.querySelectorAll('ul')[0],
    lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li"));
}

// Demo 2
var ul = document.getElementsByTagName('ul')[0], 
    lis = ul.getElementsByTagName("li"); 
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li")); 
}

由於 Demo 2 中的 lis 是一個動態的 Node List, 每一次調用 lis 都會從新對文檔進行查詢,致使無限循環的問題。
而 Demo 1 中的 lis 是一個靜態的 Node List,是一個 li 集合的快照,對文檔的任何操做都不會對其產生影響。

但爲何要這樣設計呢?
其實,在 W3C 規範中對 querySelectorAll 方法有明確規定 [6]:設計

The NodeList object returned by the querySelectorAll() method must be static ([DOM], section 8).

 

那什麼是 NodeList 呢?
W3C 中是這樣說明的 [7]:code

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]:

var ul = document.getElementsByTagName('ul')[0],
    lis1 = ul.childNodes,
    lis2 = ul.children;
console.log(lis1.toString(), lis1.length);    // "[object NodeList]" 11
console.log(lis2.toString(), lis2.length);    // "[object HTMLCollection]" 4

NodeList 對象會包含文檔中的全部節點,如 Element、Text 和 Comment 等。
HTMLCollection 對象只會包含文檔中的 Element 節點。
另外,HTMLCollection 對象比 NodeList 對象 多提供了一個 namedItem 方法。

因此在現代瀏覽器中,querySelectorAll 的返回值是一個靜態的 NodeList 對象,而 getElementsBy 系列的返回值其實是一個 HTMLCollection 對象 。

 

 

[1] Selectors API Level 2
[2] Document Object Model Core
[3] http://jsbin.com/cuduyigi/1/edit?html,js,console
[4] http://jsbin.com/mabefihi/1/watch?html,js,console
[5] 
Demo 1: http://jsbin.com/daduziba/1/watch?html,js,output
Demo 2: http://jsbin.com/xuvodipo/1/watch?html,js,output
[6] Selectors API Level 2
[7] Document Object Model Core
[8] Document Object Model HTML
[9] http://jsbin.com/qijivove/1/watch?html,js,console

 

 

本文做者:Maple Jan

本文連接:http://www.cnblogs.com/maplejan/p/3887270.html

相關文章
相關標籤/搜索