JavaScript中的querySelector和querySelectorAll vs getElementsByClassName和getElementById

Nav*_*een 148 javascript

我想知道究竟是什么之间的差异querySelectorquerySelectorAll对抗 getElementsByClassNamegetElementById

这个链接我可以收集,querySelector我可以编写document.querySelector(".myclass")获取类的元素,myclassdocument.querySelector("#myid")获取ID元素myid.但我已经可以做到这一点getElementsByClassNamegetElementById.应该首选哪一个?

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

Que*_*tin 101

我想知道querySelector和querySelectorAll对getElementsByClassName和getElementById的区别究竟是什么?

语法和浏览器支持.

querySelector 当您想要使用更复杂的选择器时更有用.

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

document.querySelector("#view:_id1:inputText1")它不起作用.但是编写document.getElementById("view:_id1:inputText1")可以正常工作.有什么想法吗?

:字符有选择内部特殊的意义.你必须逃脱它.(选择器转义字符在JS字符串中也有特殊含义,所以你也必须转义).

document.querySelector("#view\\:_id1\\:inputText1")
Run Code Online (Sandbox Code Playgroud)

  • 关于性能的任何想法,哪个更好? (19认同)
  • 关于课程选择,请参阅https://jsperf.com/getelementsbyclassname-vs-queryselectorall/25.结论:一个人应该更喜欢纯javascript而不是jquery,以及特定的函数`getElementById`和`getElementsByClassName`.没有`getElementsByClassName`,className选择可以少几百倍*. (5认同)
  • 它会因浏览器而异(从版本到版本).我假设基于选择器的那些更昂贵(但不是以一种可能非常重要的方式) (3认同)

diE*_*cho 86

Mozilla文档中收集:

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

querySelector

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

querySelectorAll

返回包含节点子树内所有匹配的Element节点的NodeList,如果未找到匹配则返回空NodeList.

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

  • +1用于指出实时节点列表的区别.根据您打算如何使用结果,这是一个非常重要的区别. (28认同)
  • 什么"不活"意味着...谢谢 (7认同)
  • "live"表示在DOM运行时添加的节点,可以在newley添加的节点上运行 (7认同)

Alv*_*oro 73

关于差异,在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);
Run Code Online (Sandbox Code Playgroud)
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
Run Code Online (Sandbox Code Playgroud)
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>
Run Code Online (Sandbox Code Playgroud)

  • 仅举几点 - 所有旧的DOM apis返回一个节点列表,即`document.getElementsByName`,`document.getElementsByTagNameNS`或`document.getElementsByTagName`将表现出相同的行为. (2认同)
  • 一些分析表明querySelector比getElementById需要更多时间,例如https://www.dimlucas.com/index.php/2016/09/17/jquery-vs-getelementbyid-vs-queryselector/。如果我们考虑访问时间怎么办?从getElementById获得的活动节点是否比来自querySelector的静态节点花费更多时间? (2认同)

Sas*_*ser 32

对于这样的回答,我指的是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)
Run Code Online (Sandbox Code Playgroud)

详细信息,技巧和示例

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

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

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

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

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

    因为您只能在单个元素上使用getElements *,而不能在集合上使用。例如:

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

    可以写成:

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

    请注意,[0]在返回集合的每一步中,仅使用来获取集合的第一个元素,与一样,最后产生一个元素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。

  • 到目前为止,有关此主题的最准确答案。应该更多地投票。 (2认同)
  • 非常精确的内容应该放在你的博客中,Sasha (2认同)
  • 我可能会更改“主要差异 4”。类似于“实时和静态集合都包含对 DOM 元素的引用。但是,实时集合会更新 DOM 元素引用列表,而静态集合则不会” (2认同)

小智 19

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

querySelector / querySelectorAll or getElementsByClassName
Run Code Online (Sandbox Code Playgroud)

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

它对上面的2个例子进行了测试,并且还测试了jQuery的等效选择器.我的测试结果如下:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
Run Code Online (Sandbox Code Playgroud)

  • 哇,这是一个_巨大的_差异,感谢您查找。显然 `querySelectorAll` 需要在幕后进行额外的工作(包括解析选择器表达式、考虑伪元素等),而 `getElementsByClassName` 只是一个递归对象遍历。 (2认同)

alg*_*thm 16

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

'#id.class:pseudo'

// or

'tag #id .class .class.class'
Run Code Online (Sandbox Code Playgroud)

getElementByClassName你可以定义一个类

'class'
Run Code Online (Sandbox Code Playgroud)

getElementById你可以定义一个id

'id'
Run Code Online (Sandbox Code Playgroud)

  • "作者被告知,虽然允许在选择器中使用伪元素,但它们不会匹配文档中的任何元素,因此不会导致返回任何元素.因此,建议作者避免使用伪 - 选择器中传递给本规范中定义的方法的元素." http://www.w3.org/TR/selectors-api/#grammar (3认同)
  • 但是``first`显然不是``first-child`. (2认同)

Jan*_*čič 7

querySelector并且querySelectorAll是一个相对较新的API,getElementById而且 getElementsByClassName已经和我们在一起很长时间了.这意味着您使用的内容主要取决于您需要支持的浏览器.

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

  • 这不一定是真的.例如,`querySelectorAll`在IE8中可用,而`getElementsByClassName`则不可用. (13认同)

mzo*_*zoz 5

querySelector是 w3c选择器 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")); 
}
Run Code Online (Sandbox Code Playgroud)