querySelector et querySelectorAll vs getElementsByClassName et getElementById en JavaScript


165

J'aimerais savoir quelle est exactement la différence entre querySelectoret querySelectorAllcontre getElementsByClassNameet getElementById?

À partir de ce lien, je pourrais comprendre qu'avec querySelectorje peux écrire document.querySelector(".myclass")pour obtenir des éléments avec une classe myclasset document.querySelector("#myid")pour obtenir un élément avec un ID myid. Mais je peux déjà faire ça getElementsByClassNameet getElementById. Lequel doit être préféré?

Je travaille également dans XPages où l'ID est généré dynamiquement avec deux points et ressemble à ceci view:_id1:inputText1. Donc quand j'écris document.querySelector("#view:_id1:inputText1")ça ne marche pas. Mais l'écriture document.getElementById("view:_id1:inputText1")fonctionne. Des idées pourquoi?


1
querySelector est utilisé pour interroger un arbre DOM HTML qui peut inclure un élément html et ses attributs comme éléments clés pour l'interrogation ... vous pouvez utiliser une expression régulière pour y parvenir .. dojo.query () fait la même chose
anix

1
Tu ne veux pas dire document.querySelectorAll(".myclass")? L'utilisation document.querySelector(".myclass")ne retournera que le premier élément qui correspond.
mhatch

Réponses:


113

Je voudrais savoir quelle est exactement la différence entre querySelector et querySelectorAll par rapport à getElementsByClassName et getElementById?

La syntaxe et le support du navigateur.

querySelector est plus utile lorsque vous souhaitez utiliser des sélecteurs plus complexes.

Par exemple, tous les éléments de la liste descendant d'un élément membre de la classe foo: .foo li

document.querySelector ("# view: _id1: inputText1") cela ne fonctionne pas. Mais l'écriture de document.getElementById ("view: _id1: inputText1") fonctionne. Des idées pourquoi?

Le :caractère a une signification particulière dans un sélecteur. Vous devez y échapper. (Le caractère d'échappement de sélection a une signification particulière dans une chaîne JS aussi, donc vous devez échapper que trop).

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

3
Cela variera d'un navigateur à l'autre (et d'une version à l'autre). Je suppose que ceux basés sur les sélecteurs étaient plus chers (mais pas d'une manière qui sera probablement significative)
Quentin

1
Je soutiens la déclaration de @ janaspage. Le site est également en panne aujourd'hui.
doplumi

6
Et à propos de la sélection de classe, voir aussi jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Conclusion: il faut bien plus préférer le javascript pur que jquery, et les fonctions spécifiques getElementByIdet getElementsByClassName. La sélection className peut être plusieurs centaines de fois plus lente sans getElementsByClassName.
Atrahasis

101

collecte de la documentation Mozilla:

L'interface NodeSelector Cette spécification ajoute deux nouvelles méthodes à tout objet implémentant les interfaces Document, DocumentFragment ou Element:

querySelector

Renvoie le premier nœud Element correspondant dans le sous-arbre du nœud. Si aucun nœud correspondant n'est trouvé, null est renvoyé.

querySelectorAll

Renvoie une NodeList contenant tous les nœuds Element correspondants dans le sous-arbre du nœud, ou une NodeList vide si aucune correspondance n'est trouvée.

et

Remarque: la liste de nœuds renvoyée par querySelectorAll()n'est pas active , ce qui signifie que les modifications apportées au DOM ne sont pas reflétées dans la collection. Ceci est différent des autres méthodes d'interrogation DOM qui renvoient des listes de nœuds en direct.


32
+1 pour souligner la distinction de la liste de nœuds en direct. C'est une différence extrêmement importante à prendre en compte en fonction de la façon dont vous comptez utiliser les résultats.
jmbpiano

7
«live» signifie nœud ajouté dans le runtime DOM et peut fonctionner sur ce nœud ajouté
newley

83

Concernant les différences, il y en a une importante dans les résultats entre querySelectorAll et getElementsByClassName: la valeur de retour est différente. querySelectorAllretournera une collection statique, tandis que getElementsByClassNamerenvoie une collection en direct. Cela peut prêter à confusion si vous stockez les résultats dans une variable pour une utilisation ultérieure:

  • Une variable générée avec querySelectorAllcontiendra les éléments qui remplissaient le sélecteur au moment où la méthode a été appelée .
  • Une variable générée avec getElementsByClassNamecontiendra les éléments qui ont rempli le sélecteur lors de son utilisation (qui peuvent être différents du moment où la méthode a été appelée).

Par exemple, remarquez comment même si vous n'avez pas réaffecté les variables aux1et aux2, elles contiennent des valeurs différentes après la mise à jour des classes:

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


2
Juste pour mentionner - Tous les anciens API DOM retournant une liste de nœuds document.getElementsByName, document.getElementsByTagNameNSou document.getElementsByTagNameprésenteront le même comportement.
RBT

2
Certaines analyses indiquent que querySelector prend plus de temps que getElementById, comme ici dimlucas.com/index.php/2016/09/17/… . Et si nous prenons en compte le temps d'accès? Le nœud actif obtenu à partir de getElementById prend-il plus de temps que le nœud statique de querySelector?
Eric

1
@RBT Je mentionnerais que ces anciennes API DOM ne renvoient pas d'objets NodeList, elles renvoient HTMLCollections.
Miscreant

@Eric document.getElementById()ne renvoie pas de nœud actif . C'est plus rapide que document.querySelector('#id_here')probablement car querySelectoril faudra d'abord analyser le sélecteur CSS.
Miscreant

68

Pour cette réponse, je me réfère à querySelectoret querySelectorAllque querySelector * et getElementById, getElementsByClassName, getElementsByTagNameet getElementsByNameque getElement *.

Différences principales

  1. querySelector * est plus flexible, car vous pouvez lui transmettre n'importe quel sélecteur CSS3, pas seulement des sélecteurs simples pour l'identifiant, la balise ou la classe.
  2. Les performances de querySelector changent avec la taille du DOM sur lequel il est appelé. * Pour être précis, les appels querySelector * s'exécutent en temps O (n) et les appels getElement * s'exécutent en temps O (1), où n est le nombre total de tous les enfants de l'élément ou du document sur lequel il est appelé. Ce fait semble être le moins connu, alors je le dis.
  3. Les appels getElement * retournent des références directes au DOM, tandis que querySelector * fait en interne des copies des éléments sélectionnés avant de leur renvoyer des références. Ceux-ci sont appelés éléments «vivants» et «statiques». Ce n'est PAS strictement lié aux types qu'ils renvoient. Il n'y a aucun moyen à ma connaissance de savoir si un élément est actif ou statique par programmation, car cela dépend du fait que l'élément a été copié à un moment donné et n'est pas une propriété intrinsèque des données. Les modifications apportées aux éléments actifs s'appliquent immédiatement - la modification d'un élément actif le modifie directement dans le DOM, et par conséquent, la ligne suivante de JS peut voir ce changement, et il se propage immédiatement à tous les autres éléments actifs référençant cet élément. Les modifications apportées aux éléments statiques ne sont réécrites dans le DOM qu'une fois l'exécution du script actuel terminée.
  4. Les types de retour de ces appels varient. querySelectoret les getElementByIddeux renvoient un seul élément. querySelectorAllet les getElementsByNamedeux renvoient des listes de nœuds, étant des fonctions plus récentes qui ont été ajoutées après que HTMLCollection soit passé de mode. Les plus anciens getElementsByClassNameet les getElementsByTagNamedeux renvoient des HTMLCollections. Encore une fois, cela n'a pas d'importance pour le fait que les éléments soient actifs ou statiques.

Ces concepts sont résumés dans le tableau suivant.

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)

Détails, conseils et exemples

  • Les HTMLCollections ne ressemblent pas à des tableaux comme les NodeLists et ne prennent pas en charge .forEach (). Je trouve l'opérateur de propagation utile pour contourner ce problème:

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

  • Chaque élément et le global documentont accès à toutes ces fonctions à l'exception de getElementByIdet getElementsByName, qui ne sont implémentés que sur document.

  • Le chaînage des appels getElement * au lieu d'utiliser querySelector * améliorera les performances, en particulier sur les DOM très volumineux. Même sur de petits DOM et / ou avec de très longues chaînes, c'est généralement plus rapide. Cependant, à moins que vous ne sachiez que vous avez besoin des performances, la lisibilité de querySelector * doit être préférée. querySelectorAllest souvent plus difficile à réécrire, car vous devez sélectionner des éléments dans NodeList ou HTMLCollection à chaque étape. Par exemple, le code suivant ne fonctionne pas :

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`.
  • Étant donné que tous les éléments ont accès à la fois aux appels querySelector * et getElement *, vous pouvez créer des chaînes en utilisant les deux appels, ce qui peut être utile si vous voulez un gain de performances, mais ne pouvez pas éviter un querySelector qui ne peut pas être écrit en termes d'appels getElement * .

  • Bien qu'il soit généralement facile de dire si un sélecteur peut être écrit en utilisant uniquement des appels getElement *, il y a un cas qui peut ne pas être évident:

    document.querySelectorAll(".class1.class2")

    peut être réécrit comme

    document.getElementsByClassName("class1 class2")

  • L'utilisation de getElement * sur un élément statique récupéré avec querySelector * se traduira par un élément vivant par rapport au sous-ensemble statique du DOM copié par querySelector, mais pas par rapport au DOM du document complet ... c'est là que le simple l'interprétation en direct / statique des éléments commence à s'effondrer. Vous devriez probablement éviter les situations où vous devez vous inquiéter à ce sujet, mais si vous le faites, rappelez-vous que querySelector * appelle les éléments de copie qu'ils trouvent avant de leur renvoyer des références, mais les appels getElement * récupèrent les références directes sans copier.

  • Aucune des deux API ne spécifie quel élément doit être sélectionné en premier s'il y a plusieurs correspondances.

  • Comme querySelector * parcourt le DOM jusqu'à ce qu'il trouve une correspondance (voir Différence principale n ° 2), ce qui précède implique également que vous ne pouvez pas vous fier à la position d'un élément que vous recherchez dans le DOM pour garantir qu'il est trouvé rapidement - le Le navigateur peut parcourir le DOM en arrière, en avant, en profondeur d'abord, en largeur en premier, ou autrement. getElement * trouvera toujours des éléments à peu près dans le même laps de temps, quel que soit leur emplacement.


4
De loin la réponse la plus précise sur ce sujet. Devrait être plus voté.
SeaWarrior404

très précis devrait être mis dans votre blog, Sasha
theking2

25

Je suis venu sur cette page uniquement pour découvrir la meilleure méthode à utiliser en termes de performances, c'est-à-dire la plus rapide:

querySelector / querySelectorAll or getElementsByClassName

et j'ai trouvé ceci: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Il exécute un test sur les 2 exemples ci-dessus, en plus de tester également le sélecteur équivalent de jQuery. mes résultats de test étaient les suivants:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec

1
Wow, c'est une énorme différence, merci de l'avoir recherchée. Nécessite clairement querySelectorAllun travail supplémentaire dans les coulisses (y compris l'analyse de l'expression du sélecteur, la comptabilisation des pseudo éléments, etc.), alors qu'il getElementsByClassNames'agit simplement d'un parcours d'objet récursif.
John Weisz

18

querySelector peut être un sélecteur CSS (3) complet avec des identifiants, des classes et des pseudo-classes comme ceci:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

avec getElementByClassNamevous pouvez simplement définir une classe

'class'

avec getElementByIdvous pouvez simplement définir un identifiant

'id'

1
Est-ce :firstqu'un sélecteur CSS, maintenant? :first-class, ou :first-of-typepeut-être, mais je pensais que :firstc'était un ajout de JavaScript / jQuery / Sizzle.
David dit de réintégrer Monica le

@DavidThomas Oui, cela fait partie de CSS3. Il peut être utilisé comme ceci: css-tricks.com/almanac/selectors/f/first-child
algorhythm

2
mais :firstest, visiblement, non :first-child.
David dit de réintégrer Monica le

3
"Les auteurs sont informés que, bien que l'utilisation de pseudo-éléments dans les sélecteurs soit autorisée, ils ne correspondront à aucun élément du document et n'entraîneront donc aucun retour d'éléments. Par conséquent, il est conseillé aux auteurs d'éviter l'utilisation de pseudo- éléments dans les sélecteurs qui sont passés aux méthodes définies dans cette spécification. " w3.org/TR/selectors-api/#grammar
rich remer

De plus, il y a un bogue dans IE (bien sûr) qui l'oblige à renvoyer l'élément html racine au lieu d'une liste d'éléments vide lors de la sélection de pseudo-éléments.
riche remer

7

querySelectoret querySelectorAllsont des API relativement nouvelles, alors que getElementByIdet getElementsByClassNamesont avec nous depuis beaucoup plus longtemps. Cela signifie que ce que vous utilisez dépendra principalement des navigateurs que vous devez prendre en charge.

Quant au :, il a une signification particulière, vous devez donc l'échapper si vous devez l'utiliser comme partie d'un nom d'ID / de classe.


13
Ce n'est pas nécessairement vrai. Par exemple, querySelectorAllest disponible dans IE8, alors que ce getElementsByClassNamen'est pas le cas.
DaveJ

querySelectorAll... fondamentalement tout: caniuse.com/#search=querySelectorAll
dsdsdsdsd


5

querySelectorest de l' API de sélection w3c

getElementByest de l' API DOM w3c

IMO, la différence la plus notable est que le type de retour de querySelectorAllest une liste de nœuds statique et pour getElementsByc'est une liste de nœuds en direct. Par conséquent, la boucle dans la démo 2 ne se termine jamais car elle lisest en direct et se met à jour à chaque itération.

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

4

Différence entre "querySelector" et "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>


2

regarde ça

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

getElementById plus rapide que querySelector sur 25%

jquery est le plus lent

var q = time_my_script(function() {

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

});

console.log('querySelector: '+q+'ms');

-3

La principale différence entre querySelector et getlementbyID (Claassname, Tagname, etc.) est s'il y a plus d'un élément qui satisfait la condition querySelector ne retournera qu'une seule sortie tandis que getElementBy * retournera tous les éléments.

Prenons un exemple pour le rendre plus clair.

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

Le code ci-dessous expliquera la différence

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

Inshort si nous voulons sélectionner un seul élément, allez pour queryslector ou si nous voulons plusieurs éléments, allez pour getElement


1
getElementById ne renvoie qu'un seul élément, ce n'est pas du tout une différence entre les deux.
Timofey 'Sasha' Kondrashov
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.