首页  >  问答  >  正文

在JavaScript中,querySelector和querySelectorAll与getElementsByClassName和getElementById的区别

<p>我想知道<code>querySelector</code>和<code>querySelectorAll</code>与<code>getElementsByClassName</code>和<code>getElementById</code>之间到底有什么区别?</p> <p>从这个链接中,我了解到使用<code>querySelector</code>,我可以写<code>document.querySelector(".myclass")</code>来获取具有类名<code>myclass</code>的元素,以及<code>document.querySelector("#myid")</code>来获取具有ID<code>myid</code>的元素。但是我已经可以使用<code>getElementsByClassName</code>和<code>getElementById</code>来实现这个功能。哪个应该优先选择?</p> <p>另外,我在XPages中工作,ID是动态生成的,包含冒号,看起来像这样<code>view:_id1:inputText1</code>。所以当我写<code>document.querySelector("#view:_id1:inputText1")</code>时,它不起作用。但是当我写<code>document.getElementById("view:_id1:inputText1")</code>时,它起作用。有任何想法为什么会这样?</p>
P粉442576165P粉442576165447 天前635

全部回复(2)我来回复

  • P粉008829791

    P粉0088297912023-08-22 20:21:16

    对于这个答案,我将querySelectorquerySelectorAll称为querySelector*,将getElementByIdgetElementsByClassNamegetElementsByTagNamegetElementsByName称为getElement*。

    这些信息的很多可以在规范中进行验证,很多是我在编写时运行的各种基准测试得出的。规范:https://dom.spec.whatwg.org/

    主要区别

    1. querySelector*更灵活,因为您可以传递任何CSS3选择器,而不仅仅是简单的id、tag或class。
    2. querySelector*的性能随其调用的DOM的大小而变化。准确地说,querySelector*调用以O(n)时间运行,而getElement*调用以O(1)时间运行,其中n是调用所在元素或文档的所有子元素的总数。
    3. 这些调用的返回类型有所不同。querySelectorgetElementById都返回单个元素。querySelectorAllgetElementsByName都返回NodeList。getElementsByClassNamegetElementsByTagName都返回HTMLCollection。NodeList和HTMLCollection都被称为元素的集合。
    4. 集合可以分别返回“live”或“static”集合。这在它们返回的实际类型中没有反映出来。getElements*调用返回live集合,而querySelectorAll返回static集合。据我理解,live集合包含对DOM中元素的引用,而static集合包含元素的副本。您还可以查看下面的@Jan Feldmann的评论,以获取不同的角度。我还没有找到一个好的方法将其纳入我的答案,但它可能是一个更准确的理解。

    这些概念在下表中总结。

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

    详细信息、提示和示例

    • HTMLCollection不像NodeList那样类似于数组,不支持.forEach()。我发现扩展运算符对绕过这个问题很有用:

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

    • 每个元素和全局document都可以访问所有这些函数,除了getElementByIdgetElementsByName,它们只在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*调用则会直接获取引用而不复制。

    • querySelector*和getElementById以前序、深度优先的方式遍历元素,在规范中称为“树顺序”。对于其他getElement*调用,从规范中我无法确定它们是否与树顺序相同,但getElementsByClassName(".someClass")[0]可能在每个浏览器中结果不可靠。getElementById("#someId")应该是可靠的,即使您的页面上有多个相同的id副本。

    • 当我在处理无限滚动页面时,我不得不研究这个问题,我认为这可能是一个常见的情况,性能成为一个问题。我们的代码中有onScroll事件,其中包含querySelectorAll调用。即使调用被限制速率,如果您滚动到足够远的位置,页面也会崩溃,此时将有太多调用迭代太多元素,浏览器无法跟上。DOM的大小在这种用例中是相关的,因此在无限滚动页面上运行的代码中,更倾向于使用getElement*调用。

    回复
    0
  • P粉238355860

    P粉2383558602023-08-22 16:58:04

    语法和浏览器支持。

    querySelector在你想要使用更复杂的选择器时更有用。

    例如,所有从属于foo类的元素的列表项:.foo li

    :字符在选择器中有特殊含义。你需要对它进行转义。(选择器转义字符在JS字符串中也有特殊含义,所以你也需要转义)。

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

    回复
    0
  • 取消回复