querySelector和querySelectorAll与JavaScript中的getElementsByClassName和getElementById


165

我想知道querySelectorquerySelectorAll反对 getElementsByClassName与之间到底有什么区别getElementById

通过此链接,我可以收集到有关内容,querySelector可以编写document.querySelector(".myclass")以获取具有class的元素myclassdocument.querySelector("#myid")获取具有ID的元素myid。但我已经可以做到这一点getElementsByClassNamegetElementById。应该首选哪一个?

我也在XPages中工作,其中ID是用冒号动态生成的,看起来像这样view:_id1:inputText1。所以当我写的时候document.querySelector("#view:_id1:inputText1")它是行不通的。但是写document.getElementById("view:_id1:inputText1")作品。有什么想法吗?


1
querySelector用于查询HTML DOM树,该树可以包含h​​tml元素及其属性作为查询的关键元素...您可以使用正则表达式来实现这一点
。dojo.query

1
不是document.querySelectorAll(".myclass")吗 使用document.querySelector(".myclass")将仅返回匹配的第一个元素。
mhatch

Answers:


113

我想知道querySelector和querySelectorAll与getElementsByClassName和getElementById之间到底有什么区别?

语法和浏览器支持。

querySelector 当您要使用更复杂的选择器时,此功能将更为有用。

例如,所有列表项均来自作为foo类成员的元素: .foo li

document.querySelector(“#view:_id1:inputText1”)无效。但是编写document.getElementById(“ view:_id1:inputText1”)可以。有什么想法吗?

:字符有选择内部特殊的意义。你必须逃避它。(选择器转义字符在JS字符串中也具有特殊含义,因此您也必须转义字符)。

document.querySelector("#view\\:_id1\\:inputText1")

3
不同的浏览器(版本和版本)会有所不同。我以为基于选择器的选择会更昂贵(但不会以可能会变得很重要的方式)
Quentin

1
我支持@janaspage的声明。网站今天也关闭了。
doplumi 2015年

6
关于类选择,另请参见jsperf.com/getelementsbyclassname-vs-queryselectorall/25。结论:一个人应该更喜欢纯JavaScript而不是jquery,并且特定的功能getElementByIdgetElementsByClassName。没有,className的选择可能会慢百倍getElementsByClassName
Atrahasis

101

Mozilla文档中收集

NodeSelector接口此规范向实现Document,DocumentFragment或Element接口的任何对象添加了两个新方法:

querySelector

返回节点的子树中的第一个匹配Element节点。如果找不到匹配的节点,则返回null。

querySelectorAll

返回一个NodeList,其中包含该节点的子树中所有匹配的Element节点;如果找不到匹配项,则返回一个空的NodeList。

注意:返回的NodeList querySelectorAll()无效,这意味着DOM中的更改不会反映在集合中。这与其他返回活动节点列表的DOM查询方法不同。


32
+1指出活动节点列表的区别。根据您打算如何使用结果,这是一个非常重要的区别。
jmbpiano

7
“活动”表示在DOM运行时中添加了节点,并且可以在该新添加的节点上工作
diEcho

83

关于差异,querySelectorAll和之间的结果中有一个重要的差异getElementsByClassName:返回值是不同的。querySelectorAll将返回静态集合,而getElementsByClassName返回实时集合。如果将结果存储在变量中以备后用,可能会造成混乱:

  • 用生成的变量querySelectorAll将包含在调用方法时满足选择器的元素。
  • 使用生成的变量getElementsByClassName将包含使用选择器满足选择器的元素(可能与调用方法的时间不同)。

例如,请注意,即使您没有重新分配变量aux1aux2,在更新类后它们如何包含不同的值:

// storing all the elements with class "blue" using the two methods
var aux1 = document.querySelectorAll(".blue");
var aux2 = document.getElementsByClassName("blue");

// write the number of elements in each array (values match)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);

// change one element's class to "blue"
document.getElementById("div1").className = "blue";

// write the number of elements in each array (values differ)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>


2
只提-所有较大的DOM API即返回一个节点列表document.getElementsByNamedocument.getElementsByTagNameNSdocument.getElementsByTagName将出现相同的行为。
RBT

2
一些分析说,querySelector比getElementById需要更多时间,例如此处dimlucas.com/index.php/2016/09/17/…。如果我们考虑访问时间怎么办?从getElementById获得的活动节点是否比来自querySelector的静态节点花费更多时间?
艾瑞克(Eric)

1
@RBT我提到这些较旧的DOM API不会返回NodeList对象,它们会返回HTMLCollections。
错误的

@Eric document.getElementById()不返回活动节点。它比document.querySelector('#id_here')可能要快,因为querySelector必须首先解析CSS选择器。
错误的

68

对于这样的回答,我指的是querySelectorquerySelectorAll作为querySelector *和getElementByIdgetElementsByClassNamegetElementsByTagName,和getElementsByName作为getElement *。

主要区别

  1. querySelector *更加灵活,因为您可以将任何CSS3选择器传递给它,而不仅仅是ID,标记或类的简单选择器。
  2. querySelector的性能随调用它的DOM的大小而变化。*确切地说,querySelector *调用在O(n)时间运行,而getElement *调用在O(1)时间运行,其中n是被调用的元素或文档的所有子代的总数。这个事实似乎鲜为人知,因此我在此加粗。
  3. getElement *调用返回对DOM的直接引用,而querySelector *在内部将所选元素的副本复制回DOM之前。这些被称为“活动”和“静态”元素。这与它们返回的类型并不严格相关。我没有办法知道是通过编程方式确定元素是活动的还是静态的,因为它取决于元素是否在某个时刻被复制了,并且不是数据的固有属性。对活动元素的更改会立即应用-更改活动元素会直接在DOM中对其进行更改,因此JS的下一行可以看到该更改,并且该更改会传播到立即引用该元素的任何其他活动元素。对静态元素的更改仅在当前脚本执行完成后才写回到DOM。
  4. 这些调用的返回类型各不相同。querySelector并且getElementById都返回一个元素。querySelectorAll并且getElementsByName都返回NodeLists,这是HTMLCollection过时后添加的新功能。年长的getElementsByClassNamegetElementsByTagName都返回HTMLCollections。再次,这本质上与元素是活动的还是静态的无关。

下表总结了这些概念。

Function               | Live? | Type           | Time Complexity
querySelector          |   N   | Element        |  O(n)
querySelectorAll       |   N   | NodeList       |  O(n)
getElementById         |   Y   | Element        |  O(1)
getElementsByClassName |   Y   | HTMLCollection |  O(1)
getElementsByTagName   |   Y   | HTMLCollection |  O(1)
getElementsByName      |   Y   | NodeList       |  O(1)

详细信息,技巧和示例

  • HTMLCollections不像NodeLists那样像数组,并且不支持.forEach()。我发现散布运算符有助于解决此问题:

    [...document.getElementsByClassName("someClass")].forEach()

  • document除了getElementById和以外,每个元素以及全局元素都可以访问所有这些功能,而这些功能getElementsByName仅在上实现document

  • 链接getElement *调用而不是使用querySelector *可以提高性能,尤其是在非常大的DOM上。即使在小型DOM和/或链条非常长的情况下,它通常也更快。但是,除非您知道需要性能,否则应该优先选择querySelector *的可读性。querySelectorAll通常很难重写,因为您必须在每个步骤中从NodeList或HTMLCollection中选择元素。例如,下面的代码并不能正常工作:

document.getElementsByClassName("someClass").getElementsByTagName("div")

because you can only use getElements* on single elements, not collections. For example:

`document.querySelector("#someId .someClass div")`

could be written as:

document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]

Note the use of `[0]` to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with `querySelector`.
  • 由于所有元素都可以访问querySelector *和getElement *调用,因此您可以使用这两个调用建立链,如果希望获得一些性能提升,这将很有用,但不能避免无法使用getElement *调用编写的querySelector 。

  • 尽管通常很容易分辨出是否只能使用getElement *调用编写选择器,但有一种情况可能并不明显:

    document.querySelectorAll(".class1.class2")

    可以改写成

    document.getElementsByClassName("class1 class2")

  • 在使用querySelector *提取的静态元素上使用getElement *会导致元素相对于querySelector复制的DOM的静态子集处于活动状态,而不是相对于整个文档DOM处于活动状态...这就是简单的地方元素的实时/静态解释开始瓦解。您可能应该避免需要为此担心的情况,但是如果这样做,请记住,querySelector *在返回对它们的引用之前会调用它们找到的复制元素,但是getElement *调用会获取直接引用而不进行复制。

  • 如果存在多个匹配项,则两个API均未指定应首先选择哪个元素。

  • 由于querySelector *会遍历DOM直到找到匹配项(请参见主要区别#2),因此上述内容还意味着您不能依靠要在DOM中查找的元素的位置来保证能够快速找到它-浏览器可以向后,向前,深度优先,广度优先或其他方式遍历DOM。无论元素的位置如何,getElement *仍将在大约相同的时间内找到它们。


4
到目前为止,有关此主题的最准确答案。应该更多地投票。
SeaWarrior404

非常准确的信息应该放在您的博客Sasha中
theking2 '19

25

我来到此页面纯粹是为了找出在性能方面可以使用的更好方法-即哪种方法更快:

querySelector / querySelectorAll or getElementsByClassName

我发现了这个:https : //jsperf.com/getelementsbyclassname-vs-queryselectorall/18

它在上面的2 x示例上运行了一个测试,此外,它还对jQuery的等效选择器进行了测试。我的测试结果如下:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec

1
哇,那是一个很大的差异,感谢您的查询。显然querySelectorAll,在幕后需要进行其他工作(包括解析选择器表达式,考虑伪元素等),而getElementsByClassName这仅仅是递归对象遍历。
John Weisz

18

querySelector 可以是具有ID,类和伪类的完整CSS(3)-Selector,如下所示:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

getElementByClassName你可以定义一个类

'class'

getElementById你可以定义一个id

'id'

1
现在:first是CSS选择器吗?:first-class,或者:first-of-type,但是我认为这:first是对JavaScript / jQuery / Sizzle的补充。
大卫说恢复莫妮卡

@DavidThomas是的,它是CSS3的一部分。可以这样使用:css-tricks.com/almanac/selectors/f/first-child
algorhythm 2015年

2
:first显然不是:first-child
大卫说恢复莫妮卡

3
“建议作者,尽管允许在选择器中使用伪元素,但它们不会与文档中的任何元素匹配,因此不会导致返回任何元素。因此,建议作者避免使用伪元素。选择器中的元素传递给本规范中定义的方法。” w3.org/TR/selectors-api/#grammar
丰富的内容2015年

另外,IE中存在一个错误(当然),该错误会导致在选择伪元素时,它返回html根元素而不是一个空元素列表。
rich remer

7

querySelectorquerySelectorAll是相对较新的API,而getElementByIdgetElementsByClassName我们在一起已经有很长时间了。这意味着您将使用的内容主要取决于您需要支持的浏览器。

至于:,它具有特殊的含义,因此如果必须将其用作ID /类名的一部分,则必须对其进行转义。


13
这不一定是真的。例如,querySelectorAll在IE8中可用,而在IE8 getElementsByClassName中不可用。
DaveJ

querySelectorAll...基本上所有内容:caniuse.com/#search=querySelectorAll
dsdsdsdsd


5

querySelector是w3c Selector API的

getElementBy是w3c DOM API

IMO最明显的区别是的返回类型querySelectorAll是静态节点列表,而getElementsBy它是活动节点列表。因此,演示2中的循环永远不会停止,因为它lis是实时的,并且在每次迭代时都会进行更新。

// Demo 1 correct
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 wrong
var ul = document.getElementsByTagName('ul')[0], 
    lis = ul.getElementsByTagName("li"); 
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li")); 
}

4

“ querySelector”和“ querySelectorAll”之间的区别

//querySelector returns single element
let listsingle = document.querySelector('li');
console.log(listsingle);


//querySelectorAll returns lit/array of elements
let list = document.querySelectorAll('li');
console.log(list);


//Note : output will be visible in Console
<ul>
<li class="test">ffff</li>
<li class="test">vvvv</li>
<li>dddd</li>
<li class="test">ddff</li>
</ul>


2

看这个

https://codepen.io/bagdaulet/pen/bzdKjL

getElementById比querySelector快25%

jQuery最慢

var q = time_my_script(function() {

    for (i = 0; i < 1000000; i++) {
         var w = document.querySelector('#ll');
    }

});

console.log('querySelector: '+q+'ms');

-3

querySelector和getlementbyID(Claassname,Tagname等)之间的主要区别在于,如果有多个元素满足条件,则querySelector将仅返回一个输出,而getElementBy *将返回所有元素。

让我们考虑一个例子以使其更清楚。

 <nav id="primary" class="menu">
                            <a class="link" href="#">For Business</a>
                            <a class="link" href="#">Become an Instructor</a>
                            <a class="link" href="#">Mobile Applications</a>
                            <a class="link" href="#">Support</a>
                            <a class="link" href="#">Help</a>
   </nav> 

下面的代码将解释差异

**QUERY SELECTOR**
document.querySelector('.link'); // Output : For Business (element)

document.querySelectorAll('.link'); //Out All the element with class link

**GET ELEMENT**
document.getElementsByClassName('link') // Output : will return all the element with a class "link" but whereas in query selector it will return only one element which encounters first.

简而言之,如果我们要选择单个元素作为queryslector还是要多个元素作为getElement


1
getElementById仅返回一个元素,这根本不是两者之间的区别。
Timofey'Sasha'Kondrashov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.