querySelectorAll和getElementsByTagName有什么区别?

31

我在思考JavaScript中两种不同的选择元素的语法。

比如我想要从当前文档中选择所有的div,那么:

var divs = document.getElementsByTagName("div");
console.log("There are "+divs.length+" Divs in Document !");

会很好用。但是也有另一种方法可以这样做,比如:

var divs = document.querySelectorAll("div");
console.log("There are "+divs.length+" Divs in Document !");

当它们两个以相同的方式工作时,它们之间有何区别?

  • 哪一个更快?
  • 为什么?
  • 它们两者如何运作?
  • 谢谢您提前帮助。我已经看到了类似的问题,但它们没有满足我的需求。


    区别在于灵活性和浏览器支持。 - Salman A
    querySelectorAll是新的,因此只有新的浏览器支持。而getElementsByTagName是旧的,因此得到了广泛的支持。就是这样吗? - Vedant Terkar
    是的,在IE<8中不支持querySelectorAll。如果您想支持这些浏览器,这可能很重要。 - Salman A
    8个回答

    60

    大多数答案都是错误的。Nicolae Olariu是唯一一个回答正确的人。

    哪一个更快?为什么?

    这不是问题。真正的问题是“它是如何工作的?”

    在这个例子中,主要的区别在于:

    <!doctype html> 
    <html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Yandex</title> 
    
    </head> 
    <body> 
        <a href="((http://yandex.ru))">Яндекс</a>, 
        <a href="((http://yandex.com))">Yandex</a> 
    </body> 
    <script>
    
    var elems1 = document.getElementsByTagName('a'), // return 2 lements, elems1.length = 2 
        elems2 = document.querySelectorAll("a");  // return 2 elements, elems2.length = 2 
    
    document.body.appendChild(document.createElement("a")); 
    
    console.log(elems1.length, elems2.length);  // now elems1.length = 3! 
                                                // while elems2.length = 2
    </script>
    </html> 
    

    因为 querySelectorAll 返回的是一个静态列表(非动态更新)的元素。


    4
    明确!应该有选择两个答案作为被接受的选项:)。 - Vedant Terkar

    31

    选择器

    getElementsByTagName 只能根据元素的标签名进行选择。而querySelectorAll可以使用任何选择器,使其具有更大的灵活性和功能。

    返回值

    • gEBTN 返回一个实时的节点列表。
    • qSA 返回一个静态的节点列表。

    实时的节点列表可能很有用(您可以查询一次,存储该值,并在DOM更改时更新它),但也可能带来很多混乱,例如这个问题的示例

    通常,静态列表更容易处理。

    支持情况

    有关 gEBTNqSA 的支持情况,请参见 caniuse。

    gEBTN 的支持更广泛,但 qSA 在今天大多数使用情况相关的所有浏览器中都得到支持。

    性能

    您可能不需要关心。这些函数不太可能成为代码的瓶颈。

    我看到了关于哪个更快的冲突报告。在任何情况下,它都可能因浏览器而异。


    10

    来自MDN:

    element = document.querySelector(selectors);

    返回文档中第一个与指定选择器组匹配的元素(使用文档节点的深度优先遍历)。

    elements = element.getElementsByTagName(tagName)

    返回给定标签名的元素列表。在指定元素下搜索子树,但不包括该元素本身。返回的列表是动态的,即它会自动更新DOM树。因此,不需要多次使用相同的元素和参数调用element.getElementsByTagName。


    你忘记了链接。 - BoltClock
    8
    问题中的比较是关于 getElementsByTagName()querySelectorAll()(而不是 querySelector())之间的区别。querySelector()querySelectorAll() 的区别在于,querySelector() 返回与 "选择器" 匹配的第一个 HTML 元素的单个对象,而 querySelectorAll() 返回所有与 "选择器" 匹配的 HTML 元素的(静态)对象列表。正如您所提到的,getElementsByTagName() 返回一个“动态”节点列表。 - Kevin Fegan

    2

    querySelector 还支持其他 CSS 选择器,例如 "#id" 通过 id 获取元素,"input[type=text]" 获取所有具有 type=text 属性的输入元素。请参见 此处 以了解更多详情。

    对于像您所问的简单查询,它们可能同样快,但对于高级 CSS 选择器,使用 querySelectorAll 可能快得多(更不用说更少的代码编写),而不是手动应用一些过滤,这就是为什么像 jQuery 这样的库在浏览器支持时使用 querySelectorAll 的原因。


    1

    这里有一个关于querySelector和getElementsByTagName之间区别的示例

    在这个示例中,作者选择使用querySelector来解决问题。

    getElementsByTagName也会返回一个活动的nodeList,当我们将链接添加到内存中的无序列表时,链接会从文档中移除,集合的长度受到影响。

    因此,

    if(you don't want to change the NodeList during the follow-up script work){
        "use querySelectorAll"}
    else if(you want to change the NodeList during the follow-up script work) {
        "use getElementsByTagName" 
    }
    

    你可以在这个例子中尝试使用getElementsByTagName,但你会发现它无法工作。


    0

    选择器

    除了在其他答案中已经涵盖的返回值之外,另一个关键区别在于 getElementBy*TagName(或者 -Id -Class)和 querySelector/querySelectorAll 的差异是后者接受一个 选择器,而前者接受标签、ID 或类。使用 querySelector() 你可以做到如下事情:

    document.querySelectorAll('p.my16')
    

    使用getElementByTagName无法实现此操作。

    ForEach

    如果需要对getElements*函数的结果进行foreach循环,可以使用一个简单的技巧(spread)来实现。

    [...document.getElementsByClassName('my16')].forEach(e=>console.log(`hallo ${e}`))
    

    顺便说一下,我同意发帖者的观点,即性能高度不相关。关注手头的用例是有意义的。

    0

    这两个选择器会给出不同的输出。请查看图片。在此输入图像描述


    -1
    在这个例子中:
    <html> 
    <head> 
        <meta charset="utf-8"> 
        <title>Yandex</title> 
    </head> 
    <body> 
        <a href="((http://yandex.ru))">Яндекс</a>, 
        <a href="((http://yandex.com))">Yandex</a> 
    </body> 
    <script>
        var elems1 = document.getElementsByTagName('a'), // return 2 lements, elems1.length = 2 
        elems2 = document.querySelectorAll("a");  // return 2 elements, elems2.length = 2 
    
        document.body.appendChild(document.createElement("a")); 
    
        console.log(elems1.length, elems2.length);  // now elems1.length = 3! 
                                                    // while elems2.length = 2
    </script>
    </html>
    

    被创建的元素位于脚本标签之后,无法被querySelector读取。只有getElementsByTagName能够找到新的元素。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接