querySelector 和 querySelectorAll

规范定义

querySelector 和 querySelectorAll 方法是 W3C Selectors API Level 1规范中定义的。他们的作用是根据 CSS 选择器规范,便捷定位文档中指定元素。

目前几乎主流浏览器均支持了他们。包括 IE8(含) 以上版本、 Firefox、 Chrome、Safari、Opera。

querySelector 和 querySelectorAll 在规范中定义了如下接口:

module dom {
[Supplemental, NoInterfaceObject]
interface NodeSelector {
Element querySelector(in DOMString selectors);
NodeList querySelectorAll(in DOMString selectors);
};
Document implements NodeSelector;
DocumentFragment implements NodeSelector;
Element implements NodeSelector;
};

其实就是任何 NodeList 、Element 的实例对象和 Document DocumentFragment 的实例对象都有这两个方法。如:

  • document.querySelectorAll
  • document.querySelector
  • nodeList.querySelectorAll
  • nodeList.querySelector
  • element.querySelectorAll
  • element.querySelector

querySelectorAll 返回符合 Selector 条件的所有节点内容,是个 NodeList;querySelector 仅返回符合 Selector 条件的第一个节点内容,是个 Node。

JQuery 的 Selector

那我们怎么兼容低版本的浏览器呢?不用着急,有 JQuery 呢,这个火爆的东东早早就实现了 Selectors。

JAVASCRIPT JQuery CODE:
var alerts = $("p.warning, p.error");
// 返回 [<p class="warning">This is a sample warning</p>,<p >This is a sample error</p>]

这与使用 和querySelectorAll 结果一致。

两者间差异

再用用 element.querySelectorAll 看看:

JAVASCRIPT CODE:
var foo= document.getElementById("foo");
foo.querySelectorAll("div > p");
// 返回 [<p class="warning">This is a sample warning</p>,<p >This is a sample error</p>]
JAVASCRIPT JQuery CODE:
var foo= document.getElementById("foo");
$(foo).find("div > p")
// 返回 []

玩砸了……为什么两者返回结果不一致了呢?

我们看下传入的选择器字符串含义,不就是在 <div id="foo"> 节点下寻找 div 标签下的 p 标签么?

<div id="foo"> 节点下没有 div 标签了,当然应该返回一个空 nodeList。JQuery 返回的结果是正确的。很奇怪,难道说所有实现了 querySelector和 querySelectorAll 方法的浏览器都没遵守规范?这也太坑爹了!!

等等,我们还是先看看规范定义怎么说:

querySelectorAll : when invoked, return a NodeList containing all of the matching Element nodes within the node’s subtrees, in document order.
还有一句 :Even though the method is invoked on an element, selectors are still evaluated in the context of the entire document.

结合起来看,规范定义为选择器在以整个文档为基准,查找全部符合选择器描述的节点,判断返回的 NodeList 是否在 Element 子树内,如果是在 Element 子树内,则这些节点组成 NodeList 返回,其排序需与文档原始节点排序一致。

根据这个定义,我们看浏览器实现:

  • 先是在文档中找到所有处于 div 标签内的 p 子节点,他们是 [<p class="warning">This is a sample warning</p>, <p >This is a sample error</p>,<p>...</p>];
  • 然后对比 <div id="foo"> 节点的子树中是否含有这些 p 元素。<div id="foo"> 节点的子树中仅含有[<p class="warning">This is a sample warning</p>, <p >This is a sample error</p>],那么就返回他们吧。这与之前问题例子返回结果一致。

这么说,浏览器实现没错?好吧,我们可以再做个更离谱的测试来看看:

JAVASCRIPT CODE:
var foo= document.getElementById("foo");
foo.querySelectorAll("html body div > p");
// 返回 [<p class="warning">This is a sample warning</p>,<p >This is a sample error</p>]

这次的例子是在 <div id="foo"> 节点下寻找 html 标签中的body 标签中的 div 标签的直接子标签 P。

他的返回结果依然是 [<p class="warning">This is a sample warning</p>,<p >This is a sample error</p>]

这与规范说明一致。

这么说,浏览器本身实现并没有问题,而是JQuery有问题了?其实这也并不尽然,JQuery 本身并没有宣布遵守 W3C Selectors API Level 1 规范实现查找结果,他的选择器 API 实现是私有的。

对于 Element 下的选择器范围,JQuery 认为是从当前元素开始查找,返回符合的结果集。而规范恰恰指出的是选择器只针对当前文档,选择出的结果集再与当前元素的子树比较。

正是由于以上的不同导致了他们返回结果不一致。

NodeList 和 HTMLCollection之间的关系?

历史上的DOM集合接口。主要不同在于HTMLCollection是元素集合而NodeList是节点集合(即可以包含元素,也可以包含文本节点)。所以 node.childNodes 返回 NodeList,而 node.children 和 node.getElementsByXXX 返回 HTMLCollection 。

唯一要注意的是 querySelectorAll 返回的虽然是 NodeList ,但是实际上是元素集合,并且是静态的(其他接口返回的HTMLCollection和NodeList都是live的)。事实上,将来浏览器将增加 queryAll 接口取代现在的 querySelectorAll,返回 Elements 是 Array 的子类(因而可以使用Array上的forEach、map等方法)。

历史上dom1、dom2乃至dom3标准都是分core/XML和HTML部分的。getElementsByTagName是在core里的(即XML也有的),所以不可能返回HTMLCollection。但是现在的dom标准已经不分core和html了,反映的是浏览器的实现。
NodeList跟HTMLCollection有个差异是前者没有namedItem()方法后者是有的

querySelectorAll 与jquery.find 与htmlcollection 的区别的更多相关文章

  1. jQuery介绍 DOM对象和jQuery对象的转换与区别

    jQuery介绍 DOM对象和jQuery对象的转换与区别 jQuery介绍      jQuery: http://jquery.com/      write less, do more.   j ...

  2. jquery生产和开发的区别

    今天说一下jquery生产和开发的区别,在我们下载jquery的时候,会有两个下载链接,一个是jquery.min.js .迷你版 (生产),另一个是 jquery.js .开发版 .不知道的人可能就 ...

  3. JQuery this和$(this)的区别及获取$(this)子元素对象的方法

    1.JQuery this和$(this)的区别 相信很多刚接触JQuery的人,很多都会对$(this)和this的区别模糊不清,那么这两者有什么区别呢? 首先来看看JQuery中的  $()  这 ...

  4. 转: JQuery this和$(this)的区别及获取$(this)子元素对象的方法

    1.JQuery this和$(this)的区别 相信很多刚接触JQuery的人,很多都会对$(this)和this的区别模糊不清,那么这两者有什么区别呢? 首先来看看JQuery中的  $()  这 ...

  5. Jquery中$与$.fn的区别

    Jquery中$与$.fn的区别 当今web开发往往离不开Jquery的使用,Jquery以其简洁的使用方式.良好的浏览器兼容性赢得了软件研发同行的青睐,作为其中的一员,自然也不例外,尽管刚开始时很排 ...

  6. jQuery方法find()与children()区别

    一.find() 1.1 说明 find()方法返回被选元素的后代元素,一路向下直到最后一个后代. 1.2 示例 <div> <p> <span>1</spa ...

  7. jquery的trigger和triggerHandler区别

    网上关于这个问题都是抄来抄去的,都没怎么说清楚.所以自己做了个测试,供大家参考指教.首先先看API怎么说的 为了检验一下,编写了一个简单的测试代码,如下: <html lang="en ...

  8. jQuery - 01. jQuery特点、如何使用jQuery、jQuery入口函数、jQuery和DOM对象的区别、jQuery选择器、

    this指的是原生js的DOM对象 .css(“”):只写一个值是取值,写俩值是赋值 window.onload   ===   $(document).ready(); $(“”):获取元素   标 ...

  9. JQuery学习:jquery对象和js对象区别和转换

    JQuery对象与JS对象区别与转换 1.JQuery对象在操作时,更加方便 2.JQuery对象和js对象方法不通用 3.两者相互转换 *  jq -- > js:jq对象[索引]  或者  ...

随机推荐

  1. The 15th UESTC Programming Contest Preliminary C - C0ins cdoj1554

    地址:http://acm.uestc.edu.cn/#/problem/show/1554 题目: C0ins Time Limit: 3000/1000MS (Java/Others)     M ...

  2. 性能调优之MySQL篇一:MySQL性能计数器

    计数器 计数器分析 Threads_connected 表示当前有多少个客户连接该mysql服务器,连接数是否过多,网络是否存在问题,它是动态变化的,当达到最大连接数时,数据库系统就不能提供更多的连接 ...

  3. 【Thinking in Java, 4e】初始化与清理

    [用构造器确保初始化] [方法重载] 涉及基本类型的重载 1.如果传入的数据类型小于方法中声明的形式参数类型:实际数据类型会被提升. 2.如果传入的数据类型大于方法中声明的形式参数类型:编译器报错,应 ...

  4. mysql搜索不区分大小写

    mysql搜索是不区分大小写的,这种情况下我们有两种方法解决 知识前提: BINARY binary不是函数,而是一个类型转换运算符,它用来强制字符串为一个二进制字符串,可以理解为在字符串比较的时候区 ...

  5. 20145302张薇《Java程序设计》实验四报告

    20145325张薇 实验四:Andoid开发基础 实验内容 使用 Android Studio 设计"Hello" 设计过程 首先创建项目 选择.xml中的`Design 选中W ...

  6. git 总结命令

    git 命令 创建git版本库:git init 查看状态:git status 把文件添加到暂存区:git add 把文件提交到版本库:git commit  -m "提交说明" ...

  7. Oracle邮件推送函数

    CREATE OR REPLACE PROCEDURE PROCSENDEMAIL ( P_TXT VARCHAR2, P_SUB VARCHAR2, P_SENDOR VARCHAR2, P_REC ...

  8. codeforces 848c - two TVs

    2017-08-22 15:42:44 writer:pprp 参考:http://blog.csdn.net/qq_37497322/article/details/77463376#comment ...

  9. C# winfrom listview 多窗口调用

    Form1 private void button1_Click(object sender, EventArgs e) { Form f = new Form2(ref listView1); f. ...

  10. Nginx的坑

    Nginx的重启命令:./nginx -s reload  有时候没有效果,原因不知, 要重启可以使用:killall nginx,然后./nginx  (就是先kill掉Nginx,然后再重启Ngi ...