querySelector e querySelectorAll vs getElementsByClassName e getElementById em JavaScript

165

Gostaria de saber qual é exatamente a diferença entre querySelectore querySelectorAllcontra getElementsByClassNamee getElementById?

A partir desta ligação que eu poderia recolher que, com querySelectoreu posso escrever document.querySelector(".myclass")para obter elementos com classe myclasse document.querySelector("#myid")para obter elemento com ID myid. Mas eu já posso fazer isso getElementsByClassNamee getElementById. Qual deles deve ser preferido?

Também trabalho em XPages, onde o ID é gerado dinamicamente com dois pontos e se parece com isso view:_id1:inputText1. Então, quando eu escrevo document.querySelector("#view:_id1:inputText1"), não funciona. Mas escrever document.getElementById("view:_id1:inputText1")funciona. Alguma idéia do porquê?

Naveen
fonte
1
querySelector é usado para consultar uma árvore HTML DOM que pode incluir o elemento html e seus atributos como elementos principais para a consulta ... você pode usar expressões regulares para conseguir isso. dojo.query () faz a mesma coisa
anix
1
Você não quer dizer document.querySelectorAll(".myclass")? Usar document.querySelector(".myclass")retornará apenas o primeiro elemento correspondente.
Mhatch 26/05

Respostas:

113

Gostaria de saber qual é exatamente a diferença entre querySelector e querySelectorAll em relação a getElementsByClassName e getElementById?

A sintaxe e o suporte ao navegador.

querySelector é mais útil quando você deseja usar seletores mais complexos.

Por exemplo, todos os itens da lista descendem de um elemento que é membro da classe foo: .foo li

document.querySelector ("# view: _id1: inputText1") não funciona. Mas escrever document.getElementById ("view: _id1: inputText1") funciona. Alguma idéia do porquê?

O :personagem tem um significado especial dentro de um seletor. Você tem que escapar disso. (O caractere de escape do seletor também tem um significado especial em uma cadeia de caracteres JS, portanto, você também deve escapar disso ).

document.querySelector("#view\\:_id1\\:inputText1")
Quentin
fonte
3
Isso variará de navegador para navegador (e de versão para versão). Eu supor que os baseados seletor eram mais caros (mas não de uma forma que jamais deverá ser significativo)
Quentin
1
Apoio a declaração de @ janaspage. O site também está inativo hoje.
doplumi
6
E sobre a seleção de classes, consulte também jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Conclusão: deve-se preferir muito mais o javascript puro do que o jquery, e as funções específicas getElementByIde getElementsByClassName. A seleção className pode ser algumas centenas de vezes mais lenta sem getElementsByClassName.
Atrahasis
101

coletando da Documentação Mozilla:

A interface NodeSelector Esta especificação adiciona dois novos métodos a qualquer objeto que implemente as interfaces Document, DocumentFragment ou Element:

querySelector

Retorna o primeiro nó do elemento correspondente dentro da subárvore do nó. Se nenhum nó correspondente for encontrado, nulo será retornado.

querySelectorAll

Retorna um NodeList contendo todos os nós correspondentes do elemento na subárvore do nó ou um NodeList vazio se nenhuma correspondência for encontrada.

e

Nota: O NodeList retornado por querySelectorAll()não está ativo , o que significa que as alterações no DOM não são refletidas na coleção. Isso é diferente de outros métodos de consulta DOM que retornam listas de nós ativos.

diEcho
fonte
32
+1 para apontar a distinção da lista de nós ativos. Essa é uma diferença extremamente importante para estar ciente, dependendo de como você pretende usar os resultados.
jmbpiano
7
meios "ao vivo" nó adicionado no DOM tempo de execução e pode trabalhar em que newley nó adicionado
diEcho
83

Sobre as diferenças, há uma importante nos resultados entre querySelectorAlle getElementsByClassName: o valor de retorno é diferente. querySelectorAllretornará uma coleção estática, enquanto getElementsByClassNameretorna uma coleção ao vivo. Isso pode causar confusão se você armazenar os resultados em uma variável para uso posterior:

  • Uma variável gerada com querySelectorAllconterá os elementos que preencheram o seletor no momento em que o método foi chamado .
  • Uma variável gerada com getElementsByClassNameconterá os elementos que atenderam ao seletor quando ele for usado (que pode ser diferente do momento em que o método foi chamado).

Por exemplo, observe como até mesmo se você não tiver transferido as variáveis aux1e aux2, eles contêm valores diferentes depois de atualizar as 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>

Alvaro Montoro
fonte
2
Apenas para mencionar - Todas as APIs DOM anteriores que retornam uma lista de nós document.getElementsByName, document.getElementsByTagNameNSou document.getElementsByTagNameexibem o mesmo comportamento.
RBT 11/10
2
Algumas análises dizem que o querySelector leva mais tempo que o getElementById, como aqui dimlucas.com/index.php/2016/09/17/… . E se levarmos em conta o tempo de acesso? O nó ativo obtido de getElementById leva mais tempo que o estático do querySelector?
Eric
1
@RBT Eu mencionaria que essas APIs DOM mais antigas não retornam objetos NodeList, elas retornam HTMLCollections.
precisa saber é o seguinte
@Eric document.getElementById()não retorna um nó ativo . É mais rápido do que document.querySelector('#id_here')provavelmente porque querySelectorterá que analisar primeiro o seletor de CSS.
precisa saber é o seguinte
68

Para esta resposta, refiro-me querySelectore querySelectorAllcomo querySelector * e getElementById, getElementsByClassName, getElementsByTagName, e getElementsByNamecomo GetElement *.

Principais diferenças

  1. querySelector * é mais flexível, pois você pode passar para ele qualquer seletor CSS3, não apenas os simples para identificação, tag ou classe.
  2. O desempenho do querySelector muda com o tamanho do DOM no qual é chamado. * Para ser mais preciso, as chamadas querySelector * são executadas em O (n) tempo e as chamadas getElement * são executadas em O (1), em que n é o número total de todos os filhos do elemento ou documento em que é chamado. Esse fato parece ser o menos conhecido, então estou em negrito.
  3. As chamadas getElement * retornam referências diretas ao DOM, enquanto o querySelector * faz internamente cópias dos elementos selecionados antes de retornar referências a eles. Estes são referidos como elementos "ao vivo" e "estáticos". Isso NÃO está estritamente relacionado aos tipos que eles retornam. Não há como saber se um elemento está ativo ou estático programaticamente, pois depende se o elemento foi copiado em algum momento e não é uma propriedade intrínseca dos dados. As alterações nos elementos ativos são aplicadas imediatamente - a alteração de um elemento ativo o altera diretamente no DOM e, portanto, a próxima linha de JS pode ver essa alteração, e se propaga para qualquer outro elemento ativo que faça referência a esse elemento imediatamente. Alterações nos elementos estáticos são gravadas apenas no DOM após a execução do script atual.
  4. Os tipos de retorno dessas chamadas variam. querySelectore getElementByIdambos retornam um único elemento. querySelectorAlle getElementsByNameambos retornam NodeLists, sendo funções mais recentes que foram adicionadas depois que o HTMLCollection saiu de moda. Os mais antigos getElementsByClassNamee os getElementsByTagNamedois retornam HTMLCollections. Novamente, isso é essencialmente irrelevante para saber se os elementos são vivos ou estáticos.

Esses conceitos estão resumidos na tabela a seguir.

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)

Detalhes, dicas e exemplos

  • As HTMLCollections não são tão parecidas com matrizes quanto as NodeLists e não suportam .forEach (). Acho o operador spread útil para contornar isso:

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

  • Todos os elementos e o global documenttêm acesso a todas essas funções, exceto getElementByIde getElementsByName, as quais são implementadas apenas document.

  • Encadear chamadas getElement * em vez de usar querySelector * melhorará o desempenho, especialmente em DOMs muito grandes. Mesmo em DOMs pequenos e / ou com cadeias muito longas, geralmente é mais rápido. No entanto, a menos que você saiba que precisa do desempenho, a legibilidade do querySelector * deve ser preferida. querySelectorAllgeralmente é mais difícil reescrever, porque você deve selecionar elementos do NodeList ou HTMLCollection a cada etapa. Por exemplo, o código a seguir não 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`.
  • Como todos os elementos têm acesso às chamadas querySelector * e getElement *, você pode criar cadeias usando as duas chamadas, o que pode ser útil se você quiser obter algum ganho de desempenho, mas não pode evitar um querySelector que não possa ser gravado em termos das chamadas getElement * .

  • Embora seja geralmente fácil saber se um seletor pode ser gravado usando apenas chamadas getElement *, há um caso que pode não ser óbvio:

    document.querySelectorAll(".class1.class2")

    pode ser reescrito como

    document.getElementsByClassName("class1 class2")

  • O uso de getElement * em um elemento estático buscado com querySelector * resultará em um elemento que está ativo com relação ao subconjunto estático do DOM copiado por querySelector, mas não com relação ao documento completo DOM ... é aqui que o simples a interpretação ao vivo / estática dos elementos começa a desmoronar. Você provavelmente deve evitar situações em que precisa se preocupar com isso, mas, se o fizer, lembre-se de que querySelector * chama elementos de cópia que eles encontram antes de retornar referências a eles, mas as chamadas getElement * buscam referências diretas sem copiar.

  • Nenhuma API especifica qual elemento deve ser selecionado primeiro se houver várias correspondências.

  • Como o querySelector * itera pelo DOM até encontrar uma correspondência (consulte a Diferença principal nº 2), o exposto acima também implica que você não pode confiar na posição de um elemento que está procurando no DOM para garantir que ele seja encontrado rapidamente. o navegador pode percorrer o DOM para trás, para frente, profundidade primeiro, largura primeiro ou de outra forma. O getElement * ainda encontrará elementos aproximadamente na mesma quantidade de tempo, independentemente de seu posicionamento.

Timofey 'Sasha' Kondrashov
fonte
4
De longe, a resposta mais precisa sobre esse tópico. Deve ser votado mais.
SeaWarrior404
muito precisa deve ser colocado em seu blog, Sasha
theking2
25

Eu vim a esta página apenas para descobrir o melhor método para usar em termos de desempenho - ou seja, o que é mais rápido:

querySelector / querySelectorAll or getElementsByClassName

e achei o seguinte: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Ele executa um teste nos 2 x exemplos acima, além de incluir também um teste para o seletor equivalente do jQuery. meus resultados de teste foram os seguintes:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
OTurner
fonte
1
Uau, isso é uma diferença enorme , obrigado por procurar. Claramente querySelectorAllprecisa de trabalho adicional nos bastidores (incluindo a análise da expressão do seletor, a contabilização de pseudo elementos, etc.), enquanto getElementsByClassNameé apenas um percurso de objeto recursivo.
31519 John Weisz
18

querySelector pode ser um seletor CSS (3) completo com IDs e classes e pseudo-classes juntas assim:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

com getElementByClassNamevocê pode apenas definir uma classe

'class'

com getElementByIdvocê pode apenas definir um ID

'id'
algorítmico
fonte
1
:firstAgora é um seletor de CSS? :first-class, ou :first-of-typetalvez, mas achei que :firstera uma adição ao JavaScript / jQuery / Sizzle.
David diz que restabelece Monica
@DavidThomas Sim, faz parte do CSS3. Pode ser usado assim: css-tricks.com/almanac/selectors/f/first-child
algorhythm
2
mas :firsté, visivelmente, não :first-child.
David diz que restabelece Monica
3
"Os autores são avisados ​​de que, embora o uso de pseudoelementos em seletores seja permitido, eles não corresponderão a nenhum elemento do documento e, portanto, não resultariam na devolução de nenhum elemento. Portanto, recomenda-se aos autores que evitem o uso de pseudoelementos. elementos nos seletores que são passados ​​para os métodos definidos nesta especificação ". w3.org/TR/selectors-api/#grammar
rich remer
Além disso, há um bug no IE (é claro) que faz com que ele retorne o elemento html raiz em vez de uma lista vazia de elementos ao selecionar pseudo-elementos.
rich remer
7

querySelectore querySelectorAllestão relativamente novas APIs, enquanto getElementByIde getElementsByClassNametêm estado conosco por muito mais tempo. Isso significa que o que você usa dependerá principalmente de quais navegadores você precisa suportar.

Quanto ao :, ele tem um significado especial; portanto, você deve escapar se precisar usá-lo como parte de um nome de ID / classe.

Jan Hančič
fonte
13
Isto não é necessariamente verdade. Por exemplo, querySelectorAllestá disponível no IE8, enquanto getElementsByClassNamenão está.
DaveJ
querySelectorAll... basicamente tudo: caniuse.com/#search=querySelectorAll
dsdsdsdsd
1
@Naveen getelementsbyclassname vs querySelectorAll vs jquery select pode ser útil.
precisa saber é o seguinte
5

querySelectoré da API do w3c Selector

getElementByé da API DOM do w3c

Na IMO, a diferença mais notável é que o tipo de retorno querySelectorAllé uma lista de nós estáticos e, por getElementsByisso, é uma lista de nós ativos. Portanto, o loop na demonstração 2 nunca termina porque lisestá ativo e se atualiza a cada iteração.

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

Diferença entre "querySelector" e "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
fonte
2

Veja isso

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

getElementById mais rápido que querySelector em 25%

jquery é o mais lento

var q = time_my_script(function() {

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

});

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

A principal diferença entre querySelector e getlementbyID (Claassname, Tagname etc) é se houver mais de um elemento que satisfaz a condição querySelector retornará apenas uma saída, enquanto getElementBy * retornará todos os elementos.

Vamos considerar um exemplo para torná-lo mais 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> 

O código abaixo explicará a diferença

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

Por exemplo, se queremos selecionar um único elemento, vá para o queryslector ou se queremos que vários elementos, vá para getElement

ajay verma
fonte
1
getElementById retorna apenas um elemento, isso não é uma diferença entre os dois.
Timofey 'Sasha' Kondrashov