蓝戒博客

  • 首页
  • 研发说
  • 架构论
  • 效能录
  • AI谈
  • 随笔集
智构苍穹
AI为翼,架构为骨,文化为魂,实践探新境,价值筑长青。
  1. 首页
  2. 研发说
  3. 正文

querySelectorAll方法与getElementsBy系列方法异同?

2016年1月13日 6480点热度 0人点赞 0条评论

querySelectorAll 相比下面这些方法有什么区别?
getElementsByTagName
getElementsByClassName
getElementsByName

在传统的 JavaScript 开发中,查找 DOM 往往是开发人员遇到的第一个头疼的问题,原生的 JavaScript 所提供的 DOM 选择方法并不多,仅仅局限于通过 tag, name, id 等方式来查找,这显然是远远不够的,如果想要进行更为精确的选择不得不使用看起来非常繁琐的正则表达式,或者使用某个库。事实上,现在所有的浏览器厂商都提供了 querySelector 和 querySelectorAll 这两个方法的支持,甚至就连微软也派出了 IE 8 作为支持这一特性的代表,querySelector 和 querySelectorAll 作为查找 DOM 的又一途径,极大地方便了开发者,使用它们,你可以像使用 CSS 选择器一样快速地查找到你需要的节点。

querySelector 和 querySelectorAll 的使用非常的简单,就像标题说到的一样,它和 CSS 的写法完全一样,对于前端开发人员来说,这是难度几乎为零的一次学习。假如我们有一个 id 为 test 的 DIV,为了获取到这个元素,你也许会像下面这样:

document.getElementById("test");

现在我们来试试使用新方法来获取这个 DIV:

document.querySelector("#test");
document.querySelectorAll("#test")[0];

感觉区别不大是吧,但如果是稍微复杂点的情况,原始的方法将变得非常麻烦,这时候 querySelector 和 querySelectorAll 的优势就发挥出来了。比如接下来这个例子,我们将在 document 中选取 class 为 test 的 div 的子元素 p 的第一个子元素,当然这很拗口,但是用本文的新方法来选择这个元素,比用言语来描述它还要简单。

document.querySelector("div.test>p:first-child");
document.querySelectorAll("div.test>p:first-child")[0];

现在应该对于 querySelector、querySelectorAll 方法中的参数已经非常明白了,是的,它接收的参数和 CSS 选择器完全一致。querySelector 和 querySelectorAll 的区别在于 querySelector 用来获取一个元素,而querySelectorAll 可以获取多个元素。querySelector 将返回匹配到的第一个元素,如果没有匹配的元素则返回 Null。querySelectorAll 返回一个包含匹配到的元素的数组,如果没有匹配的元素则返回的数组为空。在本文最后一个例子中,我们使用 querySelectorAll 给所有 class 为 emphasis 的元素加粗显示。

var emphasisText = document.querySelectorAll(".emphasis");
for( var i = 0 , j = emphasisText.length ; i < j ; i++ ){
emphasisText[i].style.fontWeight = "bold";

这是原生方法,比起jquery速度快,缺点是IE6、7不支持。

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

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

需要注意的是,querySelectorAll 所接收的参数是必须严格符合 CSS 选择符规范的。所以下面这种写法,将会抛出异常。

代码如下 [4]:

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。看看下面这个经典的例子 [5]:

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

The NodeList interface provides the abstraction of an ordered collection of nodes, without defining o-r 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 o-r the node's name o-r 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 对象 。

5.注意点
标准里强调了querySelectorAll返回的一定是一个static NodeList -- 也就是说如果将它的返回结果保存下来,当文档更新时,保存的NodeList里的元素不会跟着更新。
W3C Selector API Level 1 规定当传入的CSS选择器不合法时,会抛出SYNTAX_ERR异常。Selector API Level 2 和 WHATWG 改为了 SyntaxError。
按照W3C Selector API Level 1的提示,在选择器里使用pseudo-elements(目前只有:after,:before,:first-letter,:first-line,:selection)将不会匹配到任何元素,另外出于保护隐私的考虑,标准也推荐将所有链接视为未访问,即:visited不会匹配到任何元素。
无匹配元素时,querySelector返回null,querySelectorAll返回空的NodeList
有多个匹配元素时,querySelector返回按照document order(先序DFS)遍历到的第一个元素,querySelectorAll返回按照 document order 排序的NodeList

参考资料:
1. http://www.zhihu.com/question/24702250
2. http://www.nowamagic.net/librarys/veda/detail/388
3. http://www.cnblogs.com/joyeecheung/p/4122959.html

标签: javascript
最后更新:2025年9月13日

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

最新 热点 随机
最新 热点 随机
npm 安全更新:把握令牌变更与发布体系的迁移参考指南 TresJS:用 Vue 构建现代化交互式 3D 体验 i18n 高效实现方案:前端国际化神器安利一波 前端国际化 i18n 实践:从项目到组件库的全链路方案 GEO(生成引擎优化)完整指南:AI 搜索时代的企业内容新机会 NativeScript:用 JavaScript / TypeScript 构建真正的原生应用
前端开源工具 PinMe:极简部署体验分享大屏适配的核心痛点与一行 autofit 解决方案markdown-exit:现代化的 Markdown 解析工具Lerna + Monorepo:前端多仓库管理的最佳实践CrewAI:基于角色协作的 AI Agent 团队框架浅析2025 最推荐的 uni-app 技术栈:unibest + uView Pro 高效开发全攻略
🧩 E2E 测试实战:Playwright 介绍与使用,对比 Cypress 的优劣势与生态选择 前端模块构建工具webpack入门教程 Sublime Text3 快捷键精华版 CSS命名规范—BEM思想 Monaco Editor真香,从对比到实战封装,一篇讲透 探索angularJS中的$watch,$apply,$digest理解双向数据绑定
最近评论
渔夫 发布于 1 个月前(11月05日) 学到了,感谢博主分享
沙拉小王子 发布于 8 年前(11月30日) 适合vue入门者学习,赞一个
沙拉小王子 发布于 8 年前(11月30日) 适合vue入门者学习,赞一个
cywcd 发布于 9 年前(04月27日) 请参考一下这篇文章http://www.jianshu.com/p/fa4460e75cd8
cywcd 发布于 9 年前(04月27日) 请参考一下这篇文章http://www.jianshu.com/p/fa4460e75cd8

COPYRIGHT © 2025 蓝戒博客_智构苍穹-专注于大前端领域技术生态. ALL RIGHTS RESERVED.

京ICP备12026697号-2