querySelector y querySelectorAll vs getElementsByClassName y getElementById en JavaScript

165

Me gustaría saber cuál es exactamente la diferencia entre querySelectory querySelectorAllcontra getElementsByClassNamey getElementById.

Desde este enlace , podría reunir eso con lo querySelectorque puedo escribir document.querySelector(".myclass")para obtener elementos con clase myclassy document.querySelector("#myid")para obtener elementos con ID myid. Pero ya puedo hacer eso getElementsByClassNamey getElementById. ¿Cuál debería ser el preferido?

También trabajo en XPages donde la ID se genera dinámicamente con dos puntos y tiene este aspecto view:_id1:inputText1. Entonces cuando escribo document.querySelector("#view:_id1:inputText1")no funciona. Pero la escritura document.getElementById("view:_id1:inputText1")funciona. Alguna idea de por qué?

Naveen
fuente
1
querySelector se utiliza para consultar un árbol HTML DOM que puede incluir elementos html y sus atributos como elementos clave para realizar consultas ... puede usar expresiones regulares para lograr esto ... dojo.query () hace lo mismo
anix
1
No quiere decir document.querySelectorAll(".myclass")? El uso document.querySelector(".myclass")solo devolverá el primer elemento que coincida.
mhatch

Respuestas:

113

Me gustaría saber cuál es exactamente la diferencia entre querySelector y querySelectorAll contra getElementsByClassName y getElementById.

La sintaxis y el soporte del navegador.

querySelector es más útil cuando desea usar selectores más complejos.

Por ejemplo, todos los elementos de la lista descienden de un elemento que es miembro de la clase foo: .foo li

document.querySelector ("# view: _id1: inputText1") no funciona. Pero escribir document.getElementById ("view: _id1: inputText1") funciona. Alguna idea de por qué?

El :personaje tiene un significado especial dentro de un selector. Tienes que escapar de eso. (El carácter de escape del selector también tiene un significado especial en una cadena JS, por lo que también debe escapar de eso ).

document.querySelector("#view\\:_id1\\:inputText1")
Quentin
fuente
3
Varía de un navegador a otro (y de una versión a otra). Supongo que los basados ​​en el selector eran más caros (pero no de una manera que probablemente sea significativa)
Quentin
1
Apoyo la declaración de @ janaspage. El sitio está caído hoy también.
doplumi
66
Y sobre la selección de clases, consulte también jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Conclusión: uno debería preferir mucho más javascript puro que jquery, y las funciones específicas getElementByIdy getElementsByClassName. La selección de className puede ser unos cientos de veces más lenta sin getElementsByClassName.
Atrahasis
101

Recopilación de documentación de Mozilla:

La interfaz NodeSelector Esta especificación agrega dos métodos nuevos a cualquier objeto que implemente las interfaces Document, DocumentFragment o Element:

querySelector

Devuelve el primer nodo Element coincidente dentro del subárbol del nodo. Si no se encuentra un nodo coincidente, se devuelve un valor nulo.

querySelectorAll

Devuelve una NodeList que contiene todos los nodos Element coincidentes dentro del subárbol del nodo, o una NodeList vacía si no se encuentran coincidencias.

y

Nota: La NodeList devuelta por querySelectorAll()no está activa , lo que significa que los cambios en el DOM no se reflejan en la colección. Esto es diferente de otros métodos de consulta DOM que devuelven listas de nodos en vivo.

diEcho
fuente
32
+1 para señalar la distinción de la lista de nodos en vivo. Es una diferencia extremadamente importante a tener en cuenta dependiendo de cómo pretenda utilizar los resultados.
jmbpiano
77
"en vivo" significa nodo agregado en tiempo de ejecución DOM y puede funcionar en ese nodo agregado
newley
83

Sobre las diferencias, hay uno importante en los resultados entre querySelectorAlly getElementsByClassName: el valor de retorno es diferente. querySelectorAlldevolverá una colección estática, mientras que getElementsByClassNamedevuelve una colección en vivo. Esto podría generar confusión si almacena los resultados en una variable para su uso posterior:

  • Una variable generada con querySelectorAllcontendrá los elementos que cumplieron con el selector en el momento en que se llamó al método .
  • Una variable generada con getElementsByClassNamecontendrá los elementos que cumplieron con el selector cuando se usa (que puede ser diferente del momento en que se llamó al método).

Por ejemplo, observe cómo, incluso si no ha reasignado las variables aux1y aux2, contienen valores diferentes después de actualizar las clases:

// 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
fuente
2
Solo para mencionar: todas las API de DOM anteriores devuelven una lista de nodos document.getElementsByName, document.getElementsByTagNameNSo document.getElementsByTagNameexhibirán el mismo comportamiento.
RBT
2
Algunos análisis dicen que querySelector lleva más tiempo que getElementById, como aquí dimlucas.com/index.php/2016/09/17/… . ¿Qué pasa si tenemos en cuenta el tiempo de acceso? ¿El nodo en vivo obtenido de getElementById toma más tiempo que el estático de querySelector?
Eric
1
@RBT Mencionaría que estas API DOM antiguas no devuelven objetos NodeList, sino que devuelven colecciones HTMLC.
Malhechor el
@Eric document.getElementById()no devuelve un nodo activo . Es más rápido que document.querySelector('#id_here')probablemente porque querySelectorprimero tendrá que analizar el selector CSS.
Malhechor el
68

Por esta respuesta, me refiero a querySelector, y querySelectorAllcomo querySelector * y para getElementById, getElementsByClassName, getElementsByTagName, y getElementsByNamecomo getElement *.

Principales diferencias

  1. querySelector * es más flexible, ya que puede pasarle cualquier selector CSS3, no solo los simples para identificación, etiqueta o clase.
  2. El rendimiento de querySelector cambia con el tamaño del DOM en el que se invoca. * Para ser precisos, las llamadas querySelector * se ejecutan en tiempo O (n) y las llamadas getElement * se ejecutan en tiempo O (1), donde n es el número total de todos los elementos secundarios del elemento o documento en el que se invoca. Este hecho parece ser el menos conocido, así que lo estoy resaltando.
  3. Las llamadas getElement * devuelven referencias directas al DOM, mientras que querySelector * internamente hace copias de los elementos seleccionados antes de devolverles referencias. Estos se denominan elementos "en vivo" y "estáticos". Esto NO está estrictamente relacionado con los tipos que devuelven. No hay forma de saber si un elemento está vivo o estático programáticamente, ya que depende de si el elemento se copió en algún momento y no es una propiedad intrínseca de los datos. Los cambios en los elementos activos se aplican de inmediato: cambiar un elemento activo lo cambia directamente en el DOM y, por lo tanto, la siguiente línea de JS puede ver ese cambio y se propaga a cualquier otro elemento activo que haga referencia a ese elemento inmediatamente. Los cambios en los elementos estáticos solo se vuelven a escribir en el DOM después de que se ejecuta la secuencia de comandos actual.
  4. Los tipos de devolución de estas llamadas varían. querySelectory getElementByIdambos devuelven un solo elemento. querySelectorAlly getElementsByNameambos devuelven NodeLists, que son funciones más nuevas que se agregaron después de que HTMLCollection pasara de moda. Los más antiguos getElementsByClassNamey los getElementsByTagNamedos devuelven colecciones HTMLC. Nuevamente, esto es esencialmente irrelevante para saber si los elementos son vivos o estáticos.

Estos conceptos se resumen en la siguiente tabla.

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)

Detalles, consejos y ejemplos

  • Las colecciones HTMLC no son tan similares a una matriz como NodeLists y no admiten .forEach (). Creo que el operador de propagación es útil para solucionar esto:

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

  • Cada elemento, y el global document, tienen acceso a todas estas funciones, excepto para getElementByIdy getElementsByName, que solo se implementan en document.

  • El encadenamiento de llamadas getElement * en lugar de usar querySelector * mejorará el rendimiento, especialmente en DOM muy grandes. Incluso en DOM pequeños y / o con cadenas muy largas, generalmente es más rápido. Sin embargo, a menos que sepa que necesita el rendimiento, se debe preferir la legibilidad de querySelector *. querySelectorAlla menudo es más difícil de reescribir, porque debe seleccionar elementos de NodeList o HTMLCollection en cada paso. Por ejemplo, el siguiente código no funciona:

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`.
  • Dado que todos los elementos tienen acceso a las consultas querySelector * y getElement *, puede hacer cadenas utilizando ambas llamadas, lo que puede ser útil si desea un aumento de rendimiento, pero no puede evitar un querySelector que no se puede escribir en términos de las llamadas getElement * .

  • Aunque generalmente es fácil saber si un selector se puede escribir usando solo llamadas getElement *, hay un caso que puede no ser obvio:

    document.querySelectorAll(".class1.class2")

    puede reescribirse como

    document.getElementsByClassName("class1 class2")

  • El uso de getElement * en un elemento estático obtenido con querySelector * dará como resultado un elemento que está activo con respecto al subconjunto estático del DOM copiado por querySelector, pero no con respecto al documento completo DOM ... aquí es donde lo simple La interpretación en vivo / estática de los elementos comienza a desmoronarse. Probablemente debería evitar situaciones en las que deba preocuparse por esto, pero si lo hace, recuerde que querySelector * llama a los elementos de copia que encuentran antes de devolverles referencias, pero getElement * llama a buscar referencias directas sin copiar.

  • Ninguna API especifica qué elemento debe seleccionarse primero si hay varias coincidencias.

  • Debido a que querySelector * itera a través del DOM hasta que encuentra una coincidencia (ver Diferencia principal # 2), lo anterior también implica que no puede confiar en la posición de un elemento que está buscando en el DOM para garantizar que se encuentre rápidamente: el el navegador puede iterar a través del DOM hacia atrás, hacia adelante, primero en profundidad, primero en ancho o de otra manera. getElement * seguirá encontrando elementos en aproximadamente la misma cantidad de tiempo, independientemente de su ubicación.

Timofey 'Sasha' Kondrashov
fuente
44
Con mucho, la respuesta más precisa sobre este tema. Debería ser votado más.
SeaWarrior404
Sasha debe poner muy precisa en su blog
theking2
25

Vine a esta página simplemente para encontrar el mejor método para usar en términos de rendimiento, es decir, cuál es más rápido:

querySelector / querySelectorAll or getElementsByClassName

y encontré esto: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Ejecuta una prueba en los 2 x ejemplos anteriores, además de lanzar una prueba para el selector equivalente de jQuery también. Los resultados de mi prueba fueron los siguientes:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
OTurner
fuente
1
Wow, esa es una gran diferencia, gracias por buscarlo. Claramente querySelectorAllnecesita trabajo adicional detrás de escena (incluido el análisis de la expresión del selector, la explicación de pseudo elementos, etc.), mientras que getElementsByClassNamees simplemente un recorrido recursivo de objetos.
John Weisz
18

querySelector puede ser un completo CSS (3) -Selector con ID y clases y pseudo-clases juntas de esta manera:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

con getElementByClassNameusted solo puede definir una clase

'class'

con getElementByIdusted solo puede definir una identificación

'id'
algoritmo
fuente
1
¿Es :firstun selector CSS, ahora? :first-classo :first-of-typetal vez, pero pensé que :firstera una adición de JavaScript / jQuery / Sizzle
David dice que reinstale a Mónica el
@DavidThomas Sí, es parte de CSS3. Se puede utilizar la siguiente manera: css-tricks.com/almanac/selectors/f/first-child
Algorhythm
2
pero :firstes, notablemente, no :first-child.
David dice que reinstale a Mónica el
3
"Se aconseja a los autores que si bien se permite el uso de pseudoelementos en los selectores, no coincidirán con ningún elemento del documento y, por lo tanto, no se devolverá ningún elemento. Por lo tanto, se recomienda a los autores evitar el uso de pseudoelementos elementos en selectores que se pasan a los métodos definidos en esta especificación ". w3.org/TR/selectors-api/#grammar
rich remer
Además, hay un error en IE (por supuesto) que hace que devuelva el elemento html raíz en lugar de una lista de elementos vacía al seleccionar pseudoelementos.
Rich Remer
7

querySelectory querySelectorAllson API relativamente nuevas, mientras que getElementByIdy getElementsByClassNamehan estado con nosotros por mucho más tiempo. Eso significa que lo que use dependerá principalmente de los navegadores que necesite admitir.

En cuanto al :, tiene un significado especial, por lo que debe escapar si tiene que usarlo como parte de un ID / nombre de clase.

Jan Hančič
fuente
13
Esto no necesariamente es cierto. Por ejemplo, querySelectorAllestá disponible en IE8, mientras getElementsByClassNameque no lo está.
DaveJ
querySelectorAll... básicamente todo: caniuse.com/#search=querySelectorAll
dsdsdsdsd
1
@Naveen getelementsbyclassname vs querySelectorAll vs jquery select podría ser útil.
lowtechsun
5

querySelectores de w3c Selector API

getElementByes de w3c DOM API

En mi opinión, la diferencia más notable es que el tipo de retorno de querySelectorAlles una lista de nodos estáticos y getElementsByes una lista de nodos en vivo. Por lo tanto, el bucle en la demostración 2 nunca termina porque lises en vivo y se actualiza durante cada iteración.

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

Diferencia entre "querySelector" y "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
fuente
2

mira este

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

getElementById más rápido que querySelector en un 25%

jquery es el más lento

var q = time_my_script(function() {

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

});

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

La principal diferencia entre querySelector y getlementbyID (Claassname, Tagname, etc.) es si hay más de un elemento que satisface la condición querySelector devolverá solo una salida, mientras que getElementBy * devolverá todos los elementos.

Consideremos un ejemplo para hacerlo más claro.

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

El siguiente código explicará la diferencia

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

Indique si queremos seleccionar un solo elemento para ir a queryslector o si queremos que varios elementos vayan a getElement

ajay verma
fuente
1
getElementById devuelve solo un elemento, esto no es una diferencia entre los dos.
Timofey 'Sasha' Kondrashov