querySelector()和getElementBy()的区别

1. W3C 标准
  • querySelectorAll 属于 W3C 中的 Selectors API 规范 。
  • getElementsBy** 系列则属于 W3C 的 DOM 规范。
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
代码示例:
var c1 = document.querySelectorAll('.b1 .c');
var c2 = document.getElementsByClassName('c');
var c3 = document.getElementsByClassName('b2')[0].getElementsByClassName('c');
  • 需要注意的是,querySelectorAll 所接收的参数是必须严格符合 CSS 选择符规范的。所以下面这种写法,将会抛出异常。
代码示例:
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 均不能以数字为开头。)
4. 返回值
  • querySelectorAll 返回的是一个 Static Node List
  • getElementsBy 系列返回的是一个 Live Node List
  • 代码示例:
// 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 1 中的 lis 是一个 静态 的 Node List,是一个 li 集合的快照,对文档的任何操作都不会对其产生影响
  • Demo 2 中的 lis 是一个 动态 的 Node List, 每一次调用 lis 都会重新对文档进行查询,导致无限循环的问题
  • 但为什么要这样设计呢?其实,在 W3C 规范中对 querySelectorAll 方法有明确规定

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

  • 那什么是 NodeList 呢?W3C 中是这样说明的

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 又是什么?HTMLCollectionW3C 的定义如下

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.

实际上,HTMLCollectionNodeList 十分相似,都是一个动态的元素集合,每次访问都需要重新对文档进行查询。两者的本质上差别在于,HTMLCollection 是属于 Document Object Model HTML 规范,而 NodeList 属于 Document Object Model Core 规范。这样说有点难理解,看看下面的例子会比较好理解

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 对象


JS原生的DOM选择符想必大家应该都清楚,例如getElementById()之类的都属于常用的选择符,但是今天在看别人的代码的时候,又发现了两个原生的选择符 querySelector()querySelectorAll() 。其实也不是今天才知道这两个方法,之前就看别人用过很多次了,但是那时还以为是jquery专用的选择符,谁让他们都有个query呢……
然后我就去查文档,发现querySelector()是用于接收一个CSS选择符,返回与该模式匹配的第一个元素, querySelectorAll() 用于选择匹配到的所有元素。
完了看到这我就有点懵,所以这俩有什么用呢?不是已经有了 getElementById()getElementsByTagName() 了吗,这两个新添加的选择符 API 意义何在?
查了《高程》并没有找到答案,最后还是百度了一堆资料,终于算是搞懂了。
简单的说,querySelector 选择符选出来的元素及元素数组是静态的,而
getElement
这种方法选出的元素是动态的。
什么叫静态的?意思是指选出的所有元素的数组,不会随着文档操作而改变。

HTML代码:

<ul>
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>
querySelector 操作元素示例如下:
var ul=document.querySelector('ul');
var list=ul.querySelectorAll('li');
for(var i=0;i<list.length;i++){
    ul.appendChild(document.createElement('li'));
}//这个时候就创建了3个新的li,添加在ul列表上。
console.log(list.length) //输出的结果仍然是3,不是此时li的数量6
getElement 操作元素示例如下:
var ul=document.getElementsByTagName('ul')[0];
var list=ul.getElementsByTagName('li');
for(var i=0;i<5;i++){
    ul.appendChild(document.createElement('li'));
}   
console.log(list.length)//此时输出的结果就是3+5=8

所以我们现在应该可以很直观的分别出两者的区别,当然本身两种方法还有兼容性方面的区别。另外这两种方法都不能查找伪类元素。

估计很多人都知道,但是也得记录下来备忘。