31

I was wondering about two different syntax of selecting element in JavaScript.

suppose if I want to select all divs from current document then:

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

Will work fine. But there is also another way of doing so, like:

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

When both of them works in the same way. What's the difference between them ?

  • Which one is faster?
  • Why?
  • How both works?
  • Thanks in advance. I've seen the questions like this but they didn't satisfied the need.

    Vedant Terkar
    • 4,553
    • 8
    • 36
    • 62

    8 Answers8

    58

    Most answeres are wrong. Nicolae Olariu is the only, who answered correcly

    Which one is faster? Why?

    are not the questions. The real question "How it works?"

    The main difference is in this example:

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

    Because querySelectorAll returns a static (not live) list of elements.

    Elis Byberi
    • 1,422
    • 1
    • 11
    • 20
    Artem A
    • 2,154
    • 2
    • 23
    • 30
    30

    Selections

    getElementsByTagName only selects elements based on their tag name. querySelectorAll can use any selector which gives it much more flexibility and power.

    Return value

    • gEBTN returns a live node list.
    • qSA returns a static node list.

    Live node lists can be useful (you can query once, store the value, and have it update as the DOM changes) but are responsible for a lot of confusion such as the example in this question.

    Usually a static list is easier to deal with.

    Support

    See caniuse for gEBTN and qSA.

    gEBTN has more support, but qSA has support in all browsers that are relevant for most use cases today.

    Performance

    You probably shouldn't care. These functions are unlikely to be a bottleneck in your code.

    I've seen conflicting reports about which is faster. It likely varies between browsers anyway.

    Quentin
    • 914,110
    • 126
    • 1,211
    • 1,335
    10

    From MDN:

      element = document.querySelector(selectors);  

    Returns the first element within the document (using depth-first pre-order traversal of the document's nodes) that matches the specified group of selectors.

      elements = element.getElementsByTagName(tagName)  

    Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments.

    Nicolae Olariu
    • 2,487
    • 2
    • 18
    • 30
    • You forgot the links. – BoltClock Aug 15 '13 at 06:24
    • 8
      The comparison in the question was between `getElementsByTagName()` and `querySelectorAll()` (not `querySelector()`). The difference between `querySelector()` and `querySelectorAll()` is that `querySelector()` returns a single object with the first HTML element that matches the "selectors", but `querySelectorAll()` returns a (static) list of objects with all the HTML elements that match the "selectors". As you have mentioned, `getElementsByTagName()` returns a "live" node list. – Kevin Fegan Oct 01 '16 at 23:48
    2

    querySelector also supports other CSS selectors such as "#id" to get an element by id, and "input[type=text]" to get all input elements with a type=text attribute. See here for more details.

    They would probably be about equally fast for simple queries like the one you asked about, but for advanced CSS selectors it is likely much faster (not to mention much less code to write) to use querySelectorAll than applying some manual filtering yourself, which is why libraries like jQuery use querySelectorAll when the browser supports it.

    devongovett
    • 4,850
    • 5
    • 34
    • 35
    1

    Here is an example about the difference between querySelector and getElementsByTagName.

    In this example,the writer choose the querySelector to solve the problem.

    The getElementsByTagName also returns a live nodeList, and when we append the links to the in-memory unordered list, the link is removed from the document, and the length of the collection is affected.

    So

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

    And you can have a try to use getElementsByTagName in this example,you will see it can't work.

    liwenkang
    • 11
    • 1
    0

    Selectors

    Apart from the return values already covered in another answers one other key difference is that getElementBy*TagName ( or -Id -Class ) and querySelector/querySelectorAll is that the latter accepts a selector where the others a tag, id or class. With querySelector() you can do things like:

    document.querySelectorAll('p.my16')
    

    which is not possible with getElementByTagName

    ForEach

    If one needs a foreach on the result of a getElements* function a simple trick (spread) will allow that.

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

    Btw. I agree with the poster that performance is highly irrelevant. It makes sense to focus on the use case at hand.

    theking2
    • 2,174
    • 1
    • 27
    • 36
    0

    Both the selectors give different outputs. Check the image.enter image description here

    -1

    In this example:

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

    the element that is created is placed after the script tag, and cannot be read by querySelector. Only the getElementsByTagName can find the new element.

    pushkin
    • 9,575
    • 15
    • 51
    • 95