En JavaScript, la différence entre querySelector et querySelectorAll et getElementsByClassName et getElementById
P粉442576165
P粉442576165 2023-08-21 21:45:39
0
2
684
<p>Je veux savoir quelle est la différence entre <code>querySelector</code> et <code>querySelectorAll</code> et <code>getElementsByClassName</code> code> Quelle est la différence ? </p> <p>À partir de ce lien, j'ai appris qu'en utilisant <code>querySelector</code>, je peux écrire <code>document.querySelector(".myclass")</code> ;code>myclass</code> et <code>document.querySelector("#myid")</code> pour obtenir l'élément avec l'ID <code>myid</code>. Mais je peux déjà obtenir cette fonctionnalité en utilisant <code>getElementsByClassName</code> et <code>getElementById</code>. Lequel faut-il privilégier ? </p> <p>De plus, je travaille dans XPages et les identifiants sont générés dynamiquement, contiennent des deux-points et ressemblent à ceci <code>view:_id1:inputText1</code>. Donc, quand j'écris <code>document.querySelector("#view:_id1:inputText1")</code>, ça ne marche pas. Mais quand j'écris <code>document.getElementById("view:_id1:inputText1")</code>, ça marche. Avez-vous une idée de la raison pour laquelle cela se produit ? </p>
P粉442576165
P粉442576165

répondre à tous(2)
P粉008829791

Pour cette réponse, j'appellerai querySelectorquerySelectorAll称为querySelector*,将getElementByIdgetElementsByClassNamegetElementsByTagNamegetElementsByNamegetElement*.

Une grande partie de ces informations peuvent être vérifiées dans la spécification, et une grande partie est dérivée de divers benchmarks que j'ai exécutés lors de l'écriture. Spécification : https://dom.spec.whatwg.org/

Principales différences

  1. querySelector* est plus flexible car vous pouvez transmettre n'importe quel sélecteur CSS3, pas seulement un simple identifiant, une balise ou une classe.
  2. Les performances de querySelector* varient en fonction de la taille du DOM sur lequel il est appelé. Pour être précis, les appels querySelector* s'exécutent en un temps O(n), tandis que les appels getElement* s'exécutent en un temps O(1), où n est le nombre total de tous les éléments enfants de l'élément ou du document sur lequel l'appel est effectué.
  3. Le type de retour de ces appels diffère. querySelectorgetElementById都返回单个元素。querySelectorAllgetElementsByName都返回NodeList。getElementsByClassNamegetElementsByTagNameLes deux renvoient HTMLCollection. NodeList et HTMLCollection sont appelés des collections d'éléments.
  4. Les collections peuvent renvoyer respectivement des collections "live" ou "statiques". Cela ne se reflète pas dans le type réel renvoyé. L'appel getElements* renvoie une collection dynamique, tandis que querySelectorAll renvoie une collection statique. D'après ma compréhension, les collections live contiennent des références à des éléments du DOM, tandis que les collections statiques contiennent des copies d'éléments. Vous pouvez également consulter le commentaire de @Jan Feldmann ci-dessous pour une perspective différente. Je n'ai pas trouvé de bon moyen d'intégrer cela dans ma réponse, mais cela pourrait constituer une compréhension plus précise.

Ces notions sont résumées dans le tableau ci-dessous.

Function               | Live? | Type           | Time Complexity
querySelector          |       | Element        |  O(n)
querySelectorAll       |   N   | NodeList       |  O(n)
getElementById         |       | Element        |  O(1)
getElementsByClassName |   Y   | HTMLCollection |  O(1)
getElementsByTagName   |   Y   | HTMLCollection |  O(1)
getElementsByName      |   Y   | NodeList       |  O(1)

Détails, conseils et exemples

  • HTMLCollection ne ressemble pas à un tableau comme NodeList et ne prend pas en charge .forEach(). J'ai trouvé l'opérateur spread utile pour contourner ce problème :

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

  • implémenté sur chaque élément et globalement document都可以访问所有这些函数,除了getElementByIdgetElementsByName,它们只在document.

  • Chaîner les appels getElement* au lieu de querySelector* améliorera les performances, en particulier sur les très grands DOM. Généralement plus rapide même sur les petits DOM et/ou les très longues chaînes. Cependant, la lisibilité de querySelector* doit être préférée à la lisibilité, sauf si vous savez que vous avez besoin de performances. querySelectorAllHabituellement plus difficile à remplacer car vous devez sélectionner des éléments dans une NodeList ou une HTMLCollection à chaque étape. Par exemple, le code suivant ne fonctionne pas  :

    document.getElementsByClassName("someClass").getElementsByTagName("div")

    Parce que vous ne pouvez utiliser getElements* que sur un seul élément, pas sur une collection, mais si vous ne voulez qu'un seul élément alors :

    document.querySelector("#someId .someClass div")

    peut s'écrire :

    document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]

    Notez la même utilisation de [0],以获取集合的第一个元素,最终结果只有一个元素,就像使用querySelector à chaque étape du retour de la collection.

  • Étant donné que tous les éléments peuvent être appelés à l'aide de querySelector* et getElement*, il est possible d'enchaîner les opérations en utilisant les deux appels, ce qui est très utile lorsque vous souhaitez des gains de performances mais que vous ne pouvez pas éviter d'utiliser un querySelector qui ne peut pas être écrit avec getElement* l'appelle travaux.

  • Bien qu'il soit généralement facile de savoir si un sélecteur peut être écrit en utilisant uniquement des appels getElement*, il existe un cas où cela 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 obtenu avec querySelector* rendra l'élément dynamique par rapport au sous-ensemble statique du DOM copié par querySelector, mais statique par rapport au DOM complet du document... c'est ce que sont les éléments dynamiques/statiques simples. Voici où l’explication commence à s’effondrer. Vous devriez essayer d'éviter les situations où vous devez vous en soucier, mais si cela existe, rappelez-vous que les appels querySelector* copient les éléments qu'ils trouvent avant de renvoyer la référence, tandis que les appels getElement* obtiennent la référence directement sans copier.

  • querySelector* et getElementById以前序、深度优先的方式遍历元素,在规范中称为“树顺序”。对于其他getElement*调用,从规范中我无法确定它们是否与树顺序相同,但getElementsByClassName(".someClass")[0]可能在每个浏览器中结果不可靠。getElementById("#someId") devraient être fiables même si vous avez plusieurs copies du même identifiant sur votre page.

  • J'ai dû examiner ce problème lorsque je travaillais sur une page à défilement infini et j'ai pensé que cela pourrait être une situation courante où les performances deviennent un problème. Nous avons l'événement onScroll dans notre code qui contient l'appel querySelectorAll. Même si les appels sont limités en débit, la page plantera si vous faites défiler suffisamment loin, auquel cas il y aura trop d'appels itérant sur trop d'éléments pour que le navigateur puisse suivre. La taille du DOM est pertinente dans ce cas d'utilisation, donc dans le code exécuté sur une page à défilement infini, les appels getElement* sont préférés.

P粉238355860

Prise en charge de la syntaxe et du navigateur.

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

Par exemple, une liste de tous les éléments appartenant à la classe foo : .foo li

Les caractères

: ont une signification particulière dans les sélecteurs. Il faut y échapper. (Le caractère d'échappement du sélecteur a également une signification particulière dans les chaînes JS, vous devez donc également échapper it).

document.querySelector("#view\:_id1\:inputText1")
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal