querySelector i querySelectorAll vs getElementsByClassName i getElementById w JavaScript

165

Chciałbym wiedzieć, jaka dokładnie jest różnica między querySelectori querySelectorAllprzeciw getElementsByClassNamei getElementById?

Z tego linku mogłem zebrać, że za pomocą querySelectormogę pisać, document.querySelector(".myclass")aby uzyskać elementy z klasą myclassi document.querySelector("#myid")uzyskać element z ID myid. Ale już mogę to zrobić getElementsByClassNamei getElementById. Który powinien być preferowany?

Pracuję również w XPages, gdzie identyfikator jest dynamicznie generowany za pomocą dwukropka i wygląda tak view:_id1:inputText1. Więc kiedy piszę, document.querySelector("#view:_id1:inputText1")to nie działa. Ale pisanie document.getElementById("view:_id1:inputText1")działa. Jakieś pomysły, dlaczego?

Naveen
źródło
1
querySelector służy do odpytywania drzewa DOM HTML, które może zawierać element html i jego atrybuty jako kluczowe elementy do wykonywania zapytań ... możesz użyć wyrażeń regularnych, aby to osiągnąć .. dojo.query () robi to samo
anix
1
Nie masz na myśli document.querySelectorAll(".myclass")? Użycie document.querySelector(".myclass")zwróci tylko pierwszy pasujący element.
mhatch

Odpowiedzi:

113

Chciałbym wiedzieć, jaka dokładnie jest różnica między querySelector i querySelectorAll względem getElementsByClassName i getElementById?

Składnia i obsługa przeglądarki.

querySelector jest bardziej przydatne, gdy chcesz używać bardziej złożonych selektorów.

Np. wszystkie pozycje listy wywodzące się z elementu będącego członkiem klasy foo: .foo li

document.querySelector ("# view: _id1: inputText1") to nie działa. Ale pisanie document.getElementById ("view: _id1: inputText1") działa. Jakieś pomysły, dlaczego?

:Znak ma specjalne znaczenie wewnątrz selektora. Musisz od tego uciec. (Znak selektor ucieczka ma szczególne znaczenie w ciąg JS też, więc trzeba się uciekać , że zbyt).

document.querySelector("#view\\:_id1\\:inputText1")
Quentin
źródło
3
Będzie się różnić w zależności od przeglądarki (i od wersji do wersji). Zakładam, że te oparte na selektorach były droższe (ale nie w sposób, który nigdy nie będzie znaczący)
Quentin
1
Popieram oświadczenie @ janaspage. Witryna nie działa również dzisiaj.
doplumi
6
A o wyborze klas patrz także jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Wniosek: o wiele bardziej należy preferować czysty javascript niż jquery, a konkretne funkcje getElementByIdi getElementsByClassName. Wybór className może być kilkaset razy wolniejszy bez getElementsByClassName.
Atrahasis
101

pobieranie z Dokumentacji Mozilli:

Interfejs NodeSelector Ta specyfikacja dodaje dwie nowe metody do dowolnych obiektów implementujących interfejsy Document, DocumentFragment lub Element:

querySelector

Zwraca pierwszy pasujący węzeł elementu w poddrzewie węzła. Jeśli nie zostanie znaleziony pasujący węzeł, zwracana jest wartość null.

querySelectorAll

Zwraca listę węzłów zawierającą wszystkie zgodne węzły elementów w poddrzewie węzła lub pustą listę węzłów, jeśli nie zostaną znalezione żadne dopasowania.

i

Uwaga: lista NodeList zwrócona przez querySelectorAll()nie jest aktywna , co oznacza, że ​​zmiany w modelu DOM nie są odzwierciedlane w kolekcji. Różni się to od innych metod zapytań DOM, które zwracają aktywne listy węzłów.

diEcho
źródło
32
+1 za wskazanie rozróżnienia na liście aktywnych węzłów. To niezwykle ważna różnica, o której należy pamiętać, w zależności od tego, jak zamierzasz wykorzystać wyniki.
jmbpiano
7
„Na żywo” oznacza węzeł dodany w środowisku wykonawczym DOM i może działać na tym dodanym przez Newleya węźle
diEcho
83

Jeśli chodzi o różnice, jest jeden ważny w wynikach między querySelectorAlla getElementsByClassName: wartość zwracana jest inna. querySelectorAllzwróci kolekcję statyczną, podczas gdy getElementsByClassNamezwróci kolekcję na żywo. Może to prowadzić do nieporozumień, jeśli przechowujesz wyniki w zmiennej do późniejszego wykorzystania:

  • Zmienna wygenerowana za pomocą querySelectorAllbędzie zawierała elementy, które wypełniły selektor w momencie wywołania metody .
  • Zmienna wygenerowana za pomocą getElementsByClassNamebędzie zawierała elementy, które wypełniły selektor, gdy jest używana (mogą różnić się od momentu wywołania metody).

Na przykład zwróć uwagę, że nawet jeśli nie zmienisz przypisania zmiennych aux1i aux2, po zaktualizowaniu klas zawierają one inne wartości:

// 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
źródło
2
Wystarczy wspomnieć - Wszystkie starsze API DOM powrocie listę węzłów mianowicie document.getElementsByName, document.getElementsByTagNameNSczy document.getElementsByTagNamebędzie wykazywać takie samo zachowanie.
RBT
2
Niektóre analizy mówią, że querySelector zajmuje więcej czasu niż getElementById, jak tutaj dimlucas.com/index.php/2016/09/17/… . A jeśli weźmiemy pod uwagę czas dostępu? Czy aktywny węzeł uzyskany z getElementById zajmuje więcej czasu niż węzeł statyczny z querySelector?
Eric
1
@RBT Wspomniałbym, że te starsze interfejsy DOM API nie zwracają obiektów NodeList, zwracają HTMLCollections.
Miscreant
@Eric document.getElementById()nie zwraca aktywnego węzła. Jest to szybsze niż document.querySelector('#id_here')prawdopodobnie, ponieważ querySelectornajpierw trzeba będzie przeanalizować selektor CSS.
Zbuntowany
68

Dla tej odpowiedzi, odsyłam do querySelectori querySelectorAlljak querySelector * i getElementById, getElementsByClassName, getElementsByTagName, i getElementsByNamejak getElement *.

Główne różnice

  1. querySelector * jest bardziej elastyczny, ponieważ możesz przekazać do niego dowolny selektor CSS3, a nie tylko prosty dla identyfikatora, tagu lub klasy.
  2. Wydajność querySelector zmienia się wraz z rozmiarem modelu DOM, na którym jest wywoływana. * Mówiąc dokładniej, wywołania querySelector * są uruchamiane w czasie O (n), a wywołania getElement * w czasie O (1), gdzie n jest całkowitą liczbą wszystkich elementów podrzędnych elementu lub dokumentu, na którym jest wywoływany. Ten fakt wydaje się najmniej znany, więc śmiało.
  3. Wywołania getElement * zwracają bezpośrednie odwołania do DOM, podczas gdy querySelector * wewnętrznie kopiuje wybrane elementy przed zwróceniem do nich odwołań. Nazywa się to elementami „aktywnymi” i „statycznymi”. NIE jest to ściśle związane z typami, które zwracają. W żaden sposób nie wiem, czy element jest programowo aktywny, czy statyczny, ponieważ zależy to od tego, czy element został skopiowany w pewnym momencie i nie jest wewnętrzną właściwością danych. Zmiany w aktywnych elementach są stosowane natychmiastowo - zmiana aktywnego elementu zmienia go bezpośrednio w DOM, a zatem kolejna linia JS może zobaczyć tę zmianę i natychmiast propaguje się na inne aktywne elementy odwołujące się do tego elementu. Zmiany w elementach statycznych są zapisywane z powrotem do DOM dopiero po zakończeniu wykonywania bieżącego skryptu.
  4. Typy zwrotów tych wywołań są różne. querySelectori getElementByIdoba zwracają pojedynczy element. querySelectorAlli getElementsByNameoba zwracają NodeLists, będąc nowszymi funkcjami, które zostały dodane po tym, jak HTMLCollection wyszedł z mody. Starsze getElementsByClassNamei getElementsByTagNameoba zwracają HTMLCollections. Ponownie, nie ma to zasadniczo znaczenia dla tego, czy elementy są na żywo, czy statyczne.

Pojęcia te podsumowano w poniższej tabeli.

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)

Szczegóły, wskazówki i przykłady

  • HTMLCollections nie są tak podobne do tablic jak NodeLists i nie obsługują .forEach (). Uważam, że operator rozprzestrzeniania jest przydatny do obejścia tego:

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

  • Każdy element, także globalny document, ma dostęp do wszystkich tych funkcji z wyjątkiem getElementByIdi getElementsByName, które są zaimplementowane tylko w document.

  • Łączenie wywołań getElement * w łańcuch zamiast używania querySelector * poprawi wydajność, szczególnie w przypadku bardzo dużych DOM. Nawet na małych DOMach i / lub przy bardzo długich łańcuchach jest generalnie szybszy. Jeśli jednak nie wiesz, że potrzebujesz wydajności, preferowana powinna być czytelność querySelector *. querySelectorAlljest często trudniejsze do przepisania, ponieważ na każdym kroku musisz wybierać elementy z NodeList lub HTMLCollection. Na przykład poniższy kod nie działa:

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`.
  • Ponieważ wszystkie elementy mają dostęp zarówno do wywołań querySelector *, jak i getElement *, możesz tworzyć łańcuchy przy użyciu obu wywołań, co może być przydatne, jeśli chcesz uzyskać pewien wzrost wydajności, ale nie można uniknąć zapytania querySelector, którego nie można zapisać w kategoriach wywołań getElement * .

  • Chociaż na ogół łatwo jest stwierdzić, czy selektor można zapisać za pomocą tylko wywołań getElement *, jest jeden przypadek, który może nie być oczywisty:

    document.querySelectorAll(".class1.class2")

    można przepisać jako

    document.getElementsByClassName("class1 class2")

  • Użycie getElement * na elemencie statycznym pobranym za pomocą querySelector * spowoduje, że element będzie aktywny w odniesieniu do statycznego podzbioru DOM skopiowanego przez querySelector, ale nie będzie żył w odniesieniu do całego DOM dokumentu ... żywa / statyczna interpretacja elementów zaczyna się rozpadać. Powinieneś prawdopodobnie unikać sytuacji, w których musisz się o to martwić, ale jeśli to zrobisz, pamiętaj, że querySelector * wywołuje kopiowanie elementów, które znajdą przed zwróceniem do nich odniesień, ale wywołania getElement * pobierają bezpośrednie odniesienia bez kopiowania.

  • Żaden interfejs API nie określa, który element powinien zostać wybrany jako pierwszy, jeśli istnieje wiele dopasowań.

  • Ponieważ querySelector * iteruje przez DOM, aż znajdzie dopasowanie (patrz Główna różnica # 2), powyższe oznacza również, że nie można polegać na pozycji elementu, którego szukasz w DOM, aby zagwarantować, że zostanie on szybko znaleziony - przeglądarka może iterować przez DOM wstecz, do przodu, najpierw głębia, najpierw wszerz lub w inny sposób. getElement * nadal znajdzie elementy w mniej więcej tym samym czasie, niezależnie od ich rozmieszczenia.

Timofey „Sasha” Kondrashov
źródło
4
Zdecydowanie najdokładniejsza odpowiedź na ten temat. Powinien być bardziej poparty.
SeaWarrior404,
bardzo precyzyjne powinno być
wpisane
25

Przyszedłem na tę stronę wyłącznie po to, aby dowiedzieć się, jaka metoda jest lepsza do zastosowania pod względem wydajności - tj. Która jest szybsza:

querySelector / querySelectorAll or getElementsByClassName

i znalazłem to: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Uruchamia test na przykładach 2 x powyżej, a ponadto wsuwa test dla równoważnego selektora jQuery. moje wyniki testów były następujące:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
OTurner
źródło
1
Wow, to ogromna różnica, dzięki za sprawdzenie. Wyraźnie querySelectorAllwymaga dodatkowej pracy za kulisami (w tym analizowania wyrażenia selektora, uwzględniania pseudoelementów itp.), Podczas gdy getElementsByClassNamejest to tylko rekurencyjne przechodzenie przez obiekt.
John Weisz
18

querySelector może być kompletnym selektorem CSS (3) z identyfikatorami, klasami i pseudoklasami razem w następujący sposób:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

z getElementByClassNametobą możesz po prostu zdefiniować klasę

'class'

ze getElementByIdmożna po prostu określić identyfikator

'id'
algorytm
źródło
1
Czy :firstteraz jest selektor CSS? :first-class, a :first-of-typemoże, ale myślałem, że :firstto dodatek JavaScript / jQuery / Sizzle.
David mówi, że przywróć Monice
@DavidThomas Tak, jest częścią CSS3. Można go używać w ten sposób: css-tricks.com/almanac/selectors/f/first-child
algorhythm
2
ale :firstjest, zauważalnie, nie :first-child.
David mówi, że przywróć Monikę
3
„Informuje się autorów, że chociaż użycie pseudoelementów w selektorach jest dozwolone, to nie będą one dopasowywać żadnych elementów w dokumencie, a tym samym nie spowodują zwrócenia żadnych elementów. Dlatego zaleca się autorom unikanie stosowania pseudoelementów elementy w selektorach, które są przekazywane do metod zdefiniowanych w niniejszej specyfikacji. " w3.org/TR/selectors-api/#grammar
rich remer
Ponadto w IE występuje błąd (oczywiście), który powoduje, że zwraca główny element html zamiast pustej listy elementów podczas wybierania pseudoelementów.
bogate wspomnienie
7

querySelectori querySelectorAllsą stosunkowo nowe API, natomiast getElementByIdi getElementsByClassNamesą z nami na dużo dłużej. Oznacza to, że to, czego używasz, będzie zależeć głównie od przeglądarek, które chcesz obsługiwać.

Jeśli chodzi o :, ma on specjalne znaczenie, więc musisz go uciec, jeśli musisz go użyć jako części identyfikatora / nazwy klasy.

Jan Hančič
źródło
13
To niekoniecznie jest prawdą. Na przykład querySelectorAlljest dostępny w IE8, a getElementsByClassNamenie.
DaveJ
querySelectorAll... w zasadzie wszystko: caniuse.com/#search=querySelectorAll
dsdsdsdsd
1
Pomocne może być @Naveen getelementsbyclassname vs querySelectorAll vs jquery select .
lowtechsun
5

querySelectorjest w3c Selector API

getElementByjest w3c DOM API

IMO najbardziej zauważalną różnicą jest to, że zwracanym typem querySelectorAlljest statyczna lista węzłów, aw przypadku getElementsBywęzłów aktywna lista. Dlatego pętla w wersji demonstracyjnej 2 nigdy się nie kończy, ponieważ lisjest na żywo i aktualizuje się podczas każdej iteracji.

// 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
źródło
4

Różnica między „querySelector” i „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
źródło
2

Spójrz na to

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

getElementById szybciej niż querySelector na 25%

jquery jest najwolniejsze

var q = time_my_script(function() {

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

});

console.log('querySelector: '+q+'ms');
Багдаулет Сайын
źródło
-3

Główna różnica między querySelector i getlementbyID (Claassname, Tagname itp.) Polega na tym, że istnieje więcej niż jeden element spełniający warunek. QuerySelector zwróci tylko jedno wyjście, podczas gdy getElementBy * zwróci wszystkie elementy.

Rozważmy przykład, aby było jaśniej.

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

Poniższy kod wyjaśni różnicę

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

W skrócie, jeśli chcemy wybrać pojedynczy element, przejdź do queryslector lub jeśli chcemy, aby wiele elementów przeszło do getElement

ajay verma
źródło
1
getElementById zwraca tylko jeden element, to wcale nie jest różnica między nimi.
Timofey 'Sasha' Kondrashov