querySelector und querySelectorAll vs getElementsByClassName und getElementById in JavaScript

165

Ich würde gerne wissen, was genau der Unterschied zwischen querySelectorund querySelectorAllgegen getElementsByClassNameund ist getElementById.

Über diesen Link konnte querySelectorich feststellen, dass ich mit schreiben kann, document.querySelector(".myclass")um Elemente mit Klasse myclassund document.querySelector("#myid")Elemente mit ID zu erhalten myid. Aber das kann ich schon getElementsByClassNameund getElementById. Welches sollte bevorzugt werden?

Außerdem arbeite ich in XPages, wo die ID dynamisch mit Doppelpunkt generiert wird und so aussieht view:_id1:inputText1. Wenn ich schreibe document.querySelector("#view:_id1:inputText1"), funktioniert es nicht. Aber das Schreiben document.getElementById("view:_id1:inputText1")funktioniert. Irgendwelche Ideen warum?

Naveen
quelle
1
querySelector wird zum Abfragen eines HTML-DOM-Baums verwendet, der das HTML-Element und seine Attribute als Schlüsselelemente für das Abfragen enthalten kann. Sie können reguläre Ausdrücke verwenden, um dies zu erreichen. dojo.query () macht dasselbe
anix
1
Meinst du nicht document.querySelectorAll(".myclass")? Mit using document.querySelector(".myclass")wird nur das erste übereinstimmende Element zurückgegeben.
mhatch

Antworten:

113

Ich möchte wissen, was genau der Unterschied zwischen querySelector und querySelectorAll gegenüber getElementsByClassName und getElementById ist.

Die Syntax und die Browserunterstützung.

querySelector ist nützlicher, wenn Sie komplexere Selektoren verwenden möchten.

zB Alle Listenelemente stammen von einem Element ab, das Mitglied der foo-Klasse ist: .foo li

document.querySelector ("# view: _id1: inputText1") funktioniert nicht. Das Schreiben von document.getElementById ("view: _id1: inputText1") funktioniert jedoch. Irgendwelche Ideen warum?

Das :Zeichen hat innerhalb eines Selektors eine besondere Bedeutung. Du musst ihm entkommen. (Das Selektor Escape - Zeichen hat eine besondere Bedeutung in einem JS - String zu, so dass Sie entkommen müssen , dass auch).

document.querySelector("#view\\:_id1\\:inputText1")
QUentin
quelle
3
Es wird von Browser zu Browser (und von Version zu Version) variieren. Ich würde annehmen, dass selektorbasierte teurer waren (aber nicht in einer Weise, die jemals wahrscheinlich von Bedeutung sein wird)
Quentin
1
Ich unterstütze die Aussage von @ janaspage. Die Seite ist heute auch nicht erreichbar.
Doplumi
6
Informationen zur Klassenauswahl finden Sie auch unter jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Fazit: Man sollte reines Javascript weitaus mehr bevorzugen als jquery und die spezifischen Funktionen getElementByIdund getElementsByClassName. Die Auswahl von className kann ohne einige hundert Mal langsamer sein getElementsByClassName.
Atrahasis
101

Sammeln aus Mozilla-Dokumentation:

Die NodeSelector-Schnittstelle Diese Spezifikation fügt Objekten, die die Document-, DocumentFragment- oder Element-Schnittstellen implementieren, zwei neue Methoden hinzu:

querySelector

Gibt den ersten übereinstimmenden Elementknoten im Teilbaum des Knotens zurück. Wenn kein passender Knoten gefunden wird, wird null zurückgegeben.

querySelectorAll

Gibt eine NodeList zurück, die alle übereinstimmenden Elementknoten im Teilbaum des Knotens enthält, oder eine leere NodeList, wenn keine Übereinstimmungen gefunden werden.

und

Hinweis: Die von zurückgegebene NodeList querySelectorAll()ist nicht aktiv. Dies bedeutet, dass Änderungen im DOM nicht in der Sammlung berücksichtigt werden . Dies unterscheidet sich von anderen DOM-Abfragemethoden, die Live-Knotenlisten zurückgeben.

diEcho
quelle
32
+1 für den Hinweis auf die Unterscheidung der Live-Knotenliste. Dies ist ein äußerst wichtiger Unterschied, den Sie beachten müssen, je nachdem, wie Sie die Ergebnisse verwenden möchten.
jmbpiano
7
"live" bedeutet, dass der Knoten in der DOM-Laufzeit hinzugefügt wurde und an diesem neu hinzugefügten Knoten arbeiten kann
diEcho
83

In Bezug auf die Unterschiede gibt es einen wichtigen Punkt in den Ergebnissen zwischen querySelectorAllund getElementsByClassName: Der Rückgabewert ist unterschiedlich. querySelectorAllgibt eine statische Sammlung zurück, während getElementsByClassNameeine Live-Sammlung zurückgegeben wird. Dies kann zu Verwirrung führen, wenn Sie die Ergebnisse zur späteren Verwendung in einer Variablen speichern:

  • Eine mit generierte Variable querySelectorAllenthält die Elemente, die den Selektor zum Zeitpunkt des Aufrufs der Methode erfüllt haben .
  • Eine mit generierte Variable getElementsByClassNameenthält die Elemente, die den Selektor bei seiner Verwendung erfüllt haben (dies kann sich von dem Zeitpunkt unterscheiden, an dem die Methode aufgerufen wurde).

Zum Beispiel merken , wie auch wenn Sie die Variablen nicht neu zugewiesen haben aux1und aux2sie enthalten unterschiedliche Werte nach den Klassen der Aktualisierung:

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

Alvaro Montoro
quelle
2
Nur ganz zu schweigen - All ältere DOM apis nämlich eine Knotenliste zurückkehren document.getElementsByName, document.getElementsByTagNameNSoder document.getElementsByTagNamedas gleiche Verhalten zeigen.
RBT
2
Einige Analysen besagen, dass querySelector mehr Zeit benötigt als getElementById, wie hier dimlucas.com/index.php/2016/09/17/… . Was ist, wenn wir die Zugriffszeit berücksichtigen? Dauert der von getElementById erhaltene Live-Knoten länger als der statische von querySelector?
Eric
1
@RBT Ich würde erwähnen, dass diese älteren DOM-APIs keine NodeList-Objekte zurückgeben, sondern HTMLCollections.
Miscreant
@Eric document.getElementById()gibt keinen Live-Knoten zurück. Es ist schneller als document.querySelector('#id_here')wahrscheinlich, da querySelectorzuerst der CSS-Selektor analysiert werden muss.
Miscreant
68

Für diese Antwort verweise ich auf querySelectorund querySelectorAllals querySelector * und auf getElementById,getElementsByClassName , getElementsByTagNameund getElementsByNameals getElement *.

Hauptunterschiede

  1. querySelector * ist flexibler, da Sie ihm jeden CSS3-Selektor übergeben können, nicht nur einfache für ID, Tag oder Klasse.
  2. Die Leistung von querySelector ändert sich mit der Größe des DOM, für das es aufgerufen wird. * Um genau zu sein, werden querySelector * -Aufrufe in O (n) -Zeit und getElement * -Aufrufe in O (1) -Zeit ausgeführt, wobei n die Gesamtzahl aller untergeordneten Elemente des Elements oder Dokuments ist, für das es aufgerufen wird. Diese Tatsache scheint die am wenigsten bekannte zu sein, also kühne ich sie.
  3. getElement * -Aufrufe geben direkte Verweise auf das DOM zurück, während querySelector * intern Kopien der ausgewählten Elemente erstellt, bevor Verweise auf diese zurückgegeben werden. Diese werden als "lebende" und "statische" Elemente bezeichnet. Dies hängt NICHT eng mit den Typen zusammen, die sie zurückgeben. Ich weiß nicht, ob ein Element programmgesteuert aktiv oder statisch ist, da dies davon abhängt, ob das Element zu einem bestimmten Zeitpunkt kopiert wurde und keine intrinsische Eigenschaft der Daten ist. Änderungen an Live-Elementen werden sofort angewendet. Wenn Sie ein Live-Element ändern, wird es direkt im DOM geändert. Daher kann diese Änderung in der nächsten Zeile von JS angezeigt werden und wird sofort an alle anderen Live-Elemente weitergegeben, die auf dieses Element verweisen. Änderungen an statischen Elementen werden erst nach Ausführung des aktuellen Skripts in das DOM zurückgeschrieben.
  4. Die Rückgabetypen dieser Anrufe variieren. querySelectorund getElementByIdbeide geben ein einzelnes Element zurück. querySelectorAllund getElementsByNamebeide geben NodeLists zurück, da es sich um neuere Funktionen handelt, die hinzugefügt wurden, nachdem HTMLCollection aus der Mode gekommen war. Die älteren getElementsByClassNameund getElementsByTagNamebeide geben HTMLCollections zurück. Dies ist wiederum im Wesentlichen irrelevant, ob die Elemente aktiv oder statisch sind.

Diese Konzepte sind in der folgenden Tabelle zusammengefasst.

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)

Details, Tipps und Beispiele

  • HTMLCollections sind nicht so arrayartig wie NodeLists und unterstützen .forEach () nicht. Ich finde den Spread-Operator nützlich, um dies zu umgehen:

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

  • Jedes Element und das globale Element documenthaben Zugriff auf alle diese Funktionen mit Ausnahme von getElementByIdund getElementsByName, die nur auf implementiert sind document.

  • Das Verketten von getElement * -Aufrufen anstelle von querySelector * verbessert die Leistung, insbesondere bei sehr großen DOMs. Selbst bei kleinen DOMs und / oder mit sehr langen Ketten ist es im Allgemeinen schneller. Sofern Sie nicht wissen, dass Sie die Leistung benötigen, sollte die Lesbarkeit von querySelector * bevorzugt werden. querySelectorAllDas Umschreiben ist oft schwieriger, da Sie bei jedem Schritt Elemente aus der NodeList oder HTMLCollection auswählen müssen. Der folgende Code funktioniert beispielsweise nicht :

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`.
  • Da alle Elemente Zugriff auf die Aufrufe querySelector * und getElement * haben, können Sie mit beiden Aufrufen Ketten erstellen. Dies kann hilfreich sein, wenn Sie einen Leistungsgewinn erzielen möchten, kann jedoch einen querySelector nicht vermeiden, der nicht in Form der Aufrufe getElement * geschrieben werden kann .

  • Obwohl es im Allgemeinen leicht zu erkennen ist, ob ein Selektor nur mit getElement * -Aufrufen geschrieben werden kann, gibt es einen Fall, der möglicherweise nicht offensichtlich ist:

    document.querySelectorAll(".class1.class2")

    kann umgeschrieben werden als

    document.getElementsByClassName("class1 class2")

  • Die Verwendung von getElement * für ein statisches Element, das mit querySelector * abgerufen wird, führt zu einem Element, das in Bezug auf die statische Teilmenge des von querySelector kopierten DOM aktiv ist, jedoch nicht in Bezug auf das vollständige Dokument-DOM ... hier ist das Einfache Die Live / Static-Interpretation von Elementen beginnt auseinanderzufallen. Sie sollten wahrscheinlich Situationen vermeiden, in denen Sie sich darüber Sorgen machen müssen. Wenn Sie dies jedoch tun, denken Sie daran, dass querySelector * die gefundenen Kopierelemente aufruft, bevor Sie Verweise auf sie zurückgeben. GetElement * -Aufrufe rufen jedoch direkte Verweise ab, ohne sie zu kopieren.

  • Keine der APIs gibt an, welches Element zuerst ausgewählt werden soll, wenn mehrere Übereinstimmungen vorliegen.

  • Da querySelector * das DOM durchläuft, bis eine Übereinstimmung gefunden wird (siehe Hauptunterschied Nr. 2), bedeutet dies auch, dass Sie sich nicht auf die Position eines Elements verlassen können, nach dem Sie im DOM suchen, um sicherzustellen, dass es schnell gefunden wird - das Der Browser kann das DOM rückwärts, vorwärts, zuerst in der Tiefe, zuerst in der Breite oder auf andere Weise durchlaufen. getElement * findet Elemente unabhängig von ihrer Platzierung in ungefähr der gleichen Zeit.

Timofey 'Sasha' Kondrashov
quelle
4
Mit Abstand die genaueste Antwort zu diesem Thema. Sollte mehr positiv bewertet werden.
SeaWarrior404
sehr genau sollte in Ihrem Blog, Sasha
theking2
25

Ich bin nur auf diese Seite gekommen, um herauszufinden, welche Methode in Bezug auf die Leistung besser zu verwenden ist - dh welche ist schneller:

querySelector / querySelectorAll or getElementsByClassName

und ich fand dies: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Es führt einen Test mit den beiden obigen Beispielen durch und führt einen Test für den äquivalenten Selektor von jQuery durch. Meine Testergebnisse waren wie folgt:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
OTurner
quelle
1
Wow, das ist ein gewaltiger Unterschied, danke, dass du es nachgeschlagen hast. Benötigt eindeutig querySelectorAllzusätzliche Arbeit hinter den Kulissen (einschließlich des Parsens des Selektorausdrucks, der Berücksichtigung von Pseudoelementen usw.), während getElementsByClassNamees sich lediglich um eine rekursive Objektdurchquerung handelt.
John Weisz
18

querySelector kann eine vollständige CSS (3) -Selektor mit IDs und Klassen und Pseudoklassen zusammen sein wie folgt:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

mit können getElementByClassNameSie einfach eine Klasse definieren

'class'

mit können getElementByIdSie einfach eine ID definieren

'id'
Algorithmus
quelle
1
Ist :firstjetzt ein CSS-Selektor? :first-class, oder :first-of-typevielleicht, aber ich dachte, :firstes wäre eine JavaScript / jQuery / Sizzle-Ergänzung.
David sagt, Monica am
@ DavidThomas Ja, es ist Teil von CSS3. Es kann wie folgt
algorhythm
2
ist aber :firstmerklich nicht :first-child.
David sagt, Monica am
3
"Autoren werden darauf hingewiesen, dass die Verwendung von Pseudoelementen in Selektoren zwar zulässig ist, jedoch nicht mit Elementen im Dokument übereinstimmt und daher keine Elemente zurückgegeben werden. Daher wird den Autoren empfohlen, die Verwendung von Pseudo- Elementen zu vermeiden Elemente in Selektoren, die an die in dieser Spezifikation definierten Methoden übergeben werden. " w3.org/TR/selectors-api/#grammar
Rich Remer
Außerdem gibt es einen Fehler im IE (natürlich), der dazu führt, dass bei der Auswahl von Pseudoelementen das HTML-Stammelement anstelle einer leeren Elementliste zurückgegeben wird.
Rich Remer
7

querySelectorund querySelectorAllsind relativ neue APIs, während getElementByIdund getElementsByClassName sind schon viel länger bei uns. Das bedeutet, dass Ihre Verwendung hauptsächlich davon abhängt, welche Browser Sie unterstützen müssen.

Das :hat eine besondere Bedeutung, sodass Sie es umgehen müssen, wenn Sie es als Teil eines ID- / Klassennamens verwenden müssen.

Jan Hančič
quelle
13
Dies ist nicht unbedingt wahr. Ist beispielsweise querySelectorAllin IE8 verfügbar, getElementsByClassNamenicht jedoch.
DaveJ
querySelectorAll... im Grunde alles: caniuse.com/#search=querySelectorAll
dsdsdsdsd
1
@Naveen getelementsbyclassname vs querySelectorAll vs jquery select könnte hilfreich sein.
Lowtechsun
5

querySelectorist von w3c Selector API

getElementByist von w3c DOM API

IMO ist der bemerkenswerteste Unterschied, dass der Rückgabetyp querySelectorAlleine statische Knotenliste und getElementsByeine Live-Knotenliste ist. Daher endet die Schleife in Demo 2 nie, da sie lislive ist und sich bei jeder Iteration selbst aktualisiert.

// 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")); 
}
mzoz
quelle
4

Unterschied zwischen "querySelector" und "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>

Ambuj Khanna
quelle
2

Schau dir das an

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

getElementById ist mit 25% am schnellsten als querySelector.

jquery ist am langsamsten

var q = time_my_script(function() {

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

});

console.log('querySelector: '+q+'ms');
Багдаулет Сайын
quelle
-3

Der Hauptunterschied zwischen querySelector und getlementbyID (Claassname, Tagname usw.) besteht darin, dass mehr als ein Element die Bedingung erfüllt. QuerySelector gibt nur eine Ausgabe zurück, während getElementBy * alle Elemente zurückgibt.

Betrachten wir ein Beispiel, um es klarer zu machen.

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

Der folgende Code erklärt den Unterschied

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

Kurz gesagt, wenn wir ein einzelnes Element auswählen möchten, wählen Sie "Queryslector" oder wenn Sie mehrere Elemente auswählen möchten, wählen Sie "GetElement"

Ajay Verma
quelle
1
getElementById gibt nur ein Element zurück, dies ist überhaupt kein Unterschied zwischen den beiden.
Timofey 'Sasha' Kondrashov