轉載出處: http://www.zhihu.com/question/24702250

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

  • getElementsByTagName
  • getElementsByClassName
  • getElementsByName

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

getElementById / querySelector 这两个获取到的都是dom节点,结果没有区别。

getElement* 的实时性体现在返回集合的时候,我们知道getElementsBy*和querySelectorAll返回的都是一个节点集合,类似于数组,两种方法的区别就在于这个集合会不会自动更新。

//初始时DOMain中没有<img>元素
x = document.querySelectorAll('img')
y = document.getElementsByTagName('img')
document.body.appendChild(new Image())
x.length // 0
y.length // 1

另外,getElementById这个只能用在document上,因为正常情况下id是唯一的。

上面说了很多querySelectorAllgetElementsBy实现和原理上面的区别,我这里拿数据说话,看看两者在性能上的区别。

所有测试来源于http://jsperf.com/getelementsby-vs-queryselectorall/7,有兴趣的朋友可以自己去试试。

  • 硬件环境: Core i5-3570 3.40GHz, Win7 64bit
  • 数据格式:[ Ops/Sec] method

Ops/Sec是指每秒执行操作的次数,越高越好。

  • 浏览器1: Chrome 37.0.2062.68 32-bit
[-20,989,532] document.getElementsByTagName('a');
[----166,170] document.querySelectorAll('a');[-27,659,047] document.getElementsByName('name');
[-----79,022] document.querySelectorAll('[name=name]');[-22,972,151] document.getElementsByClassName('classname');
[-----67,003] document.querySelectorAll('[class = classname]');

点评: 
getElementBy
系列的执行速度基本都是querySelectorAll的100+倍

  • 浏览器2: Firefox 31.0 32-bit
[226,165,531] document.getElementsByTagName('a');
[----144,576] document.querySelectorAll('a');[-10,197,651] document.getElementsByName('name');
[----119,340] document.querySelectorAll('[name=name]');[227,034,307] document.getElementsByClassName('classname');
[----104,720] document.querySelectorAll('[class = classname]');

点评: 
Firefox上getElementsByTagNamegetElementsByClassName比Chrome快了10倍,而其余四个则相差无几,有高人能解析下原因么?

  • 浏览器3: IE 11.0.9600
[--1,797,107] document.getElementsByTagName('a');
[-----59,829] document.querySelectorAll('a');[--1,344,551] document.getElementsByName('name');
[-----13,706] document.querySelectorAll('[name=name]');[--1,710,804] document.getElementsByClassName('classname');
[------8,938] document.querySelectorAll('[class = classname]');

点评: 
IE比FF和Chrome慢的太多了。不过没关系:速度不够,情怀来凑嘛。

主要是选择器的区别和是否实时的区别。

1.选择器

  • querySelector**

querySelector和querySelectorAll 是HTML5新引入的功能类似jQuery的选择器。前者返回按文档顺序返回指定元素节点的子树中匹配选择器的第一个元素,没有则返回null。后者返回按文档顺序返回指定元素节点的子树中匹配选择器的元素集合,如果没有匹配返回空集合。以querySelectorAll为例说明。
querySelectorAll('selectors'),其中的selectors可以包含多个CSS选择器,可以是类选择器,也可以是ID选择器,也可以是Tag类型选择器,当然也可以是它们的混合。

elements = document.querySelectorAll('div.foo');//返回所有带foo类样式的div

  • getElementsBy***

getElementsBy***只能根据特定选择器寻找。getElementById(id)选择器内容是id名,返回拥有第一个这个id的对象引用。比如有一个
<div id="no1"><div>元素。可以用querySelector('#no1')或者getElementById('no1')获取。getElementsByTagName的选择器tagname,getElementsByName的选择器是标签的name属性值,getElementsByClassName的选择器是类名,都是直接写名字,而不需要加#,.等标识符。

2.实时性
querySelector**返回的是非实时的。而getElementBy**返回的是实时的。
用以下的例子说明:

<div id="container"><div></div><div></div>
</div>

//首先选取页面中id为container的元素
container=document.getElementById('#container'); console.log(container.childNodes.length)//结果为2 //然后通过代码为其添加一个子元素 container.appendChild(document.createElement('div')); //这个元素不但添加到页面了,这里的变量container也自动更新了 console.log(container.childNodes.length)//结果为3 

发现getElementBy的结果返回的实时的结果,而如果用querySelector,结果还是原来的结构返回结果。

转载于:https://www.cnblogs.com/shuman/p/3972910.html

[label][转载][JavaSript]querySelectorAll 方法相比 getElementsBy 系列方法有什么区别?相关推荐

  1. 图像分割的 U-Net 系列方法

    转载自https://zhuanlan.zhihu.com/p/57530767 图像分割的 U-Net 系列方法 在图像分割任务特别是医学图像分割中,U-Net[1]无疑是最成功的方法之一,该方法在 ...

  2. 调用父级方法_通信:找到任意组件实例的findComponents系列方法,5个终极方案

    已经介绍了两种组件间通信的方法:provide / inject 和 dispatch / broadcast.它们有各自的使用场景和局限,比如前者多用于子组件获取父组件的状态,后者常用于父子组件间通 ...

  3. linux+守护进程+php,【转载】Linux 守护进程的编程方法

    [转载]Linux 守护进程的编程方法 原文见: http://www.linuxdevelop.org/tingxx/show.php?table=c&id=3 Linux 守护进程的编程方 ...

  4. 图像分割的U-Net系列方法

    原文链接:https://zhuanlan.zhihu.com/p/57530767 图像分割的U-Net系列方法 在图像分割任务特别是医学图像分割中,U-Net[1]无疑是最成功的方法之一,该方法在 ...

  5. AutoCAD 2020安装失败(错误代码:1603)的解决方法/对于Autodesk系列产品都有效

    AutoCAD 2020安装失败(错误代码:1603) 这个解决方法对于Autodesk系列产品都有效 在官网找到的解决方法: 解决方案: 要处理此错误消息,请执行以下步骤: 1.找到这个文件夹C\P ...

  6. python之析构方法、item系列、hash方法、eq方法

    1.析构方法:释放一个空间之前执行 (new构造方法  申请一个空间) 某对象借用了操作系统的资源,还要通过析构方法归还回去 : 文件资源  网络资源 1)垃圾回收机制 class A:def __d ...

  7. 如何使用CNN进行物体识别和分类_基于CNN目标检测方法(RCNN系列,YOLO,SSD)

    转载自:基于CNN目标检测方法(RCNN,Fast-RCNN,Faster-RCNN,Mask-RCNN,YOLO,SSD)行人检测 一.研究意义 卷积神经网络(CNN)由于其强大的特征提取能力,近年 ...

  8. Windows系统扩充C盘空间系列方法总结

    目录 前言 方法一 使用自带的Windows的DiskPart扩充C盘 1. 打开cmd 2.三步命令 方法二:使用Windows系统内置磁盘管理扩展C盘 方法三. 使用专业磁盘分区工具 总结 前言 ...

  9. 论文:图像分割的U-Net系列方法

    膜拜大佬 &nbsp在图像分割任务特别是医学图像分割中,U-Net[1]无疑是最成功的方法之一,该方法在2015年MICCAI会议上提出,目前已达到四千多次引用.其采用的编码器(下采样)-解码 ...

最新文章

  1. apache日志分析简介
  2. go mysql 数据 json,golang查询数据返回json
  3. 【数据结构总结】第八章 排序
  4. firefox扩展开发(四) : 更多的窗口控件
  5. AFNetworking 对数据进行https ssl加密
  6. Google SRE 读书笔记 扒一扒SRE用的那些工具
  7. java中无限大_Java 9中的无限集
  8. 仿Drinkspiration App的menu
  9. 开发不能上外网怎么查资料_中考生不能复读,近一半上不了高中,怎么办?
  10. linux设备数内核选项,linux内核设备树修改指南 / linux kernel device tree modify guide
  11. vue项目引入三方字体
  12. 31、键树的插入、查找(孩子兄弟存储结构)
  13. 【LeetCode - 马化腾】第一次看到马总的代码
  14. Argis ArcToolbox-分割栅格,无结果**
  15. Spring Security和Angular教程
  16. c语言兔子序列第8年不繁殖,基于链表的兔子序列生成研究.pdf
  17. java入门基础掌握单词汇总
  18. s5pv210的工作模式
  19. ybt1000:入门测试题目
  20. 插层熔喷非织造材料的性能控制研究-数学建模大赛华数杯C题 -(分享全部解题过程)

热门文章

  1. zcmu1209(dfs)
  2. Darknet_Yolov4实战(一)_安装Ubuntu+cuda+cudnn
  3. Linux graphic subsytem(1)_概述
  4. 导出oracle sequences,CSS_oracle导出序列方法分析,方法一:SELECT ' CREATE SEQUEN - phpStudy...
  5. python爬取换页_一个可识别翻页的简易Python爬虫程序
  6. Qt5 中 关于Widget Mapper的简单应用
  7. android 视频 截图,java – android获取当前视频的截图
  8. hdu3691(无向图最小割的求解)
  9. Codeforces 1375H Set Merging (分块)
  10. find linux 目录深度_linux 查找目录或文件