Diferença entre HTMLCollection, NodeLists e arrays de objetos

93

Sempre me confundi entre HTMLCollections, objects e arrays quando se trata de DOM. Por exemplo...

  1. Qual é a diferença entre document.getElementsByTagName("td")e $("td")?
  2. $("#myTable")e $("td")são objetos (objetos jQuery). Por que o console.log também mostra a matriz de elementos DOM ao lado deles, e eles não são objetos e não são uma matriz?
  3. O que são as elusivas "NodeLists" e como faço para selecionar uma?

Forneça também qualquer interpretação do script abaixo.

Obrigado

[123,"abc",321,"cba"]=[123,"abc",321,"cba"]
{123:123,abc:"abc",321:321,cba:"cba"}=Object { 123=123, abc="abc", 321=321, more...}
Node= Node { ELEMENT_NODE=1, ATTRIBUTE_NODE=2, TEXT_NODE=3, more...}
document.links= HTMLCollection[a #, a #]
document.getElementById("myTable")= <table id="myTable">
document.getElementsByClassName("myRow")= HTMLCollection[tr.myRow, tr.myRow]
document.getElementsByTagName("td")= HTMLCollection[td, td, td, td]
$("#myTable")= Object[table#myTable]
$("td")= Object[td, td, td, td]


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> 
        <title>Collections?</title>  
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script> 
        <script type="text/javascript">
            $(function(){
                console.log('[123,"abc",321,"cba"]=',[123,"abc",321,"cba"]);
                console.log('{123:123,abc:"abc",321:321,cba:"cba"}=',{123:123,abc:"abc",321:321,cba:"cba"});
                console.log('Node=',Node);
                console.log('document.links=',document.links);
                console.log('document.getElementById("myTable")=',document.getElementById("myTable"));
                console.log('document.getElementsByClassName("myRow")=',document.getElementsByClassName("myRow"))
                console.log('document.getElementsByTagName("td")=',document.getElementsByTagName("td"));
                console.log('$("#myTable")=',$("#myTable"));
                console.log('$("td")=',$("td"));
            });
        </script>
    </head>

    <body>
        <a href="#">Link1</a>
        <a href="#">Link2</a>
        <table id="myTable">
            <tr class="myRow"><td>td11</td><td>td12</td></tr>
            <tr class="myRow"><td>td21</td><td>td22</td></tr>
        </table>
    </body> 
</html>
user1032531
fonte
Acho que devo acrescentar o seguinte para a posteridade. (a) No JavaScript moderno, uma comparação melhor seria entre document.querySelectorAll('td')e $('td'). (b) A diferença fundamental é que jQuery trabalha com seu próprio tipo de objeto que contém, entre outras coisas, uma coleção numerada de elementos HTML; essa coleção não é nenhuma das anteriores, e o objeto jQuery é essencialmente um invólucro em torno dos verdadeiros elementos DOM.
Manngo

Respostas:

112

Primeiro vou explicar a diferença entre NodeListe HTMLCollection.

Ambas as interfaces são coleções de nós DOM. Eles diferem nos métodos que fornecem e no tipo de nós que podem conter. Embora a NodeListpossa conter qualquer tipo de nó, um HTMLCollectiondeve conter apenas nós de elemento.
Um HTMLCollectionfornece os mesmos métodos que um NodeListe, adicionalmente, um método chamado namedItem.

As coleções são sempre usadas quando o acesso deve ser fornecido a vários nós, por exemplo, a maioria dos métodos seletores (como getElementsByTagName) retorna vários nós ou obtendo uma referência para todos os filhos ( element.childNodes).

Para obter mais informações, dê uma olhada na especificação DOM4 - Coleções .

Qual é a diferença entre document.getElementsByTagName("td")e $("td")?

getElementsByTagNameé o método da interface DOM. Ele aceita um nome de tag como entrada e retorna um HTMLCollection(consulte a especificação DOM4 ).

$("td")é presumivelmente jQuery. Ele aceita qualquer seletor CSS / jQuery válido e retorna um objeto jQuery.

A maior diferença entre as coleções DOM padrão e as seleções jQuery é que as coleções DOM são tipicamente ativas (nem todos os métodos retornam uma coleção ativa), ou seja, quaisquer alterações no DOM são refletidas nas coleções se forem afetadas. Eles são como uma visualização na árvore DOM, enquanto as seleções do jQuery são instantâneos da árvore DOM no momento em que a função foi chamada.

Por que console.log também mostra a matriz de elementos DOM ao lado deles, e eles não são objetos e não são uma matriz?

Os objetos jQuery são objetos do tipo array , ou seja, eles têm propriedades numéricas e uma lengthpropriedade (tenha em mente que os arrays são apenas objetos em si). Os navegadores tendem a exibir matrizes e objetos semelhantes a matrizes de uma maneira especial, como [ ... , ... , ... ].

O que são as elusivas "NodeLists" e como faço para selecionar uma?

Veja a primeira parte da minha resposta. Você não pode selecionar NodeList s, eles são o resultado de uma seleção.

Pelo que eu sei, não há nem mesmo uma maneira de criar NodeLists programaticamente (ou seja, criar um vazio e adicionar nós mais tarde), eles são retornados apenas por alguns métodos / propriedades DOM.

Felix Kling
fonte
2
@ user1032531: Bem, se você fizer qualquer alteração em um dos elementos DOM selecionados (por exemplo, adicionar um filho), é claro que verá a alteração, já que é o mesmo elemento DOM. Mas, supondo que você selecionou todos os tdelementos, adicionar um novo tdelemento posteriormente não atualizará a seleção automaticamente para conter o novo elemento.
Felix Kling,
2
@FelixKling: Você deve mencionar que nem todos NodeLists estão vivos.
Bergi,
2
Queria que todos fossem arrays
SuperUberDuper
7
Parece também que os métodos "keys", "entries" e "forEach" eu apresento em NodeList, mas ausente em HTMLCollection
Krzysztof Grzybek
2
@KrzysztofGrzybek Isso mesmo e é super irritante. Por que diabos um deles tem .forEach()e o outro não?
Robo Robok
29

0. Qual é a diferença entre um HTMLCollectione um NodeList?

Aqui estão algumas definições para você.

Especificação de DOM nível 1 - Definições de objetos diversos :

Interface HTMLCollection

Um HTMLCollection é uma lista de nós. Um nó individual pode ser acessado por índice ordinal ou pelo nome do nó ou atributos de id. Nota: As coleções no HTML DOM são consideradas ativas, o que significa que são atualizadas automaticamente quando o documento subjacente é alterado.

Especificação DOM nível 3 - NodeList

Interface NodeList

A interface NodeList fornece a abstração de uma coleção ordenada de nós, sem definir ou restringir como essa coleção é implementada. Os objetos NodeList no DOM estão ativos.

Os itens na NodeList são acessíveis por meio de um índice integral, começando em 0.

Portanto, ambos podem conter dados ativos, o que significa que o DOM será atualizado quando seus valores forem atualizados. Eles também contêm um conjunto diferente de funções.

Você notará se inspecionar o console se executar seus scripts, que o tableelemento DOM contém a childNodes NodeList[2]e a children HTMLCollection[1]. Por que eles são diferentes? Como HTMLCollectionsó pode conter nós de elemento, NodeList também contém um nó de texto.

insira a descrição da imagem aqui

1. Qual é a diferença entre document.getElementsByTagName("td")e $("td")?

document.getElementsByTagName("td")Retorna uma matriz de elementos DOM (a NodeList), $("td")é chamado um objeto jQuery que tem os elementos a partir document.getElementsByTagName("td")das suas propriedades 0, 1, 2, etc. A principal diferença é que o objeto jQuery é um pouco mais lento para recuperar, mas dá acesso a toda a calhar funções jQuery.

2. $("#myTable")e $("td")são objetos ( jQueryobjetos). Por que console.logtambém está mostrando a matriz de elementos DOM ao lado deles, e eles não são objetos e não são uma matriz?

Eles são objetos com suas propriedades 0, 1, 2, etc. conjunto com os elementos DOM. Aqui está um exemplo simples: de como funciona:

jsFiddle

    var a = {
        1: "first",
        2: "second"
    }
    alert(a[1]);

3. O que são as elusivas "NodeLists" e como faço para selecionar uma?

Você os recuperou em seu código getElementsByClassNamee getElementsByTagNameambos retornam NodeLists

NodeList

Daniel Imms
fonte
Como você exibiu o DOM em sua terceira resposta? Obrigado!
user1032531
@ user1032531 são as ferramentas de desenvolvimento do Chrome. A propósito, atualizei o início da resposta.
Daniel Imms,
O log do tipo array é principalmente um resultado da lengthpropriedade, não dos nomes numéricos das propriedades. E com o que seu exemplo de alertar uma string tem a ver console.log?
Bergi,
Isso estava mostrando como você pode ter propriedades numéricas em objetos. Estou tentando enfatizar o fato de que eles são objetos, não matrizes.
Daniel Imms,
9

Nota adicional

Qual é a diferença entre um HTMLCollection e um NodeList?

Um HTMLCollection contém apenas nós de elemento ( tags ) e um NodeList contém todos os nós .

Existem quatro tipos de nós:

  1. nó do elemento
  2. nó de atributo
  3. nó de texto
  4. nó de comentário

nodeTypes

Espaços em branco dentro dos elementos são considerados texto e o texto é considerado nós.

Considere o seguinte:

<ul id="myList">
  <!-- List items -->
  <li>List item 1</li> 
  <li>List item 2</li>
  <li>List item 3</li>
  <li>List item 4</li>
  <li>List item 5</li>
</ul>

Espaço em branco: <ul id="myList"> <li>List item</li></ul>

Sem espaço em branco: <ul id="myList"><li>List item</li></ul>

Diferença entre HTMLCollection e NodeList

Sol
fonte
2

$("td")é um objeto jQuery estendido e tem métodos jQuery, ele retorna o objeto jquery que contém uma matriz de objetos html. document.getElementsByTagName("td")é o método js bruto e retorna NodeList. Veja este artigo

karaxuna
fonte
Obrigado Karaxuna. Sim, eu tinha visto aquele artigo. Não sei se ajudou, mas definitivamente me fez fazer mais perguntas :)
user1032531
Obrigado @karaxuna. Artigo útil, muito bem explicado.
Giuseppe
0

Os objetos NodeList são coleções de Node, retornados por exemplo por x. propriedade childNodes ou método document.querySelectorAll () . Em alguns casos, o NodeList é ao vivo , o que significa que as mudanças no DOM atualizar automaticamente a coleção! Por exemplo, Node.childNodes está ativo:

var c = parent.childNodes; //assume c.length is 2
parent.appendChild(document.createElement('div'));
//now c.length is 3, despite the `c` variable is assigned before appendChild()!!
//so, do not cache the list's length in a loop.

Mas, em alguns outros casos, o NodeList é estático , onde qualquer mudança no DOM não afeta o conteúdo da coleção. querySelectorAll () retorna uma NodeList estática.

O HTMLCollection é uma coleção ativa e ordenada de elementos (é atualizada automaticamente quando o documento subjacente é alterado). Pode ser o resultado de propriedades como filhos ou métodos como document.getElementsByTagName () , e só pode ter HTMLElements como seus itens.

HTMLCollection também expõe seus membros diretamente como propriedades por nome e índice:

var f = document.forms; // this is an HTMLCollection
f[0] === f.item(0) === f.myForm //assume first form id is 'myForm'

O HTMLElement é apenas um tipo de nós:

Herança de Nó << HTMLElement

O Nó pode ser de vários tipos . Os mais importantes são os seguintes:

  • elemento (1): um nó de elemento, como <p>ou <div>.
  • atributo (2): Um atributo de um elemento. Os atributos do elemento não estão mais implementando a interface Node na especificação DOM4!
  • text (3): O texto real do elemento ou atributo.
  • comentário (8): Um nó de comentário.
  • documento (9): Um nó de documento.

Portanto, uma grande diferença é que HTMLCollection contém apenas HTMLElements, mas NodeList também contém os comentários, textos de espaço em branco (caracteres de retorno de carro, espaços ..), etc. Verifique como no seguinte trecho:

function printList(x, title) {
  console.log("\r\nprinting "+title+" (length="+x.length+"):");
  for(var i=0; i<x.length; i++) {
    console.log("  "+i+":"+x[i]);
  }
}

var elems = document.body.children; //HTMLCollection
var nodes = document.body.childNodes; //NodeList

printList(elems, "children [HTMLCollection]");
printList(nodes, "childNodes [NodeList]");
<div>para 1</div><!-- MyComment -->
<div>para 2</div>

HTMLCollection e NodeList contêm a propriedade length que você pode usar para fazer um loop sobre seus itens. Não use for ... in ou for each ... in para enumerar os itens em NodeLists, visto que eles também enumerarão suas propriedades de comprimento e item e causarão erros se seu script assumir que ele só precisa lidar com objetos de elemento. Além disso, for..in não tem garantia de visitar as propriedades em nenhuma ordem específica.

for (var i = 0; i < myNodeList.length; i++) {
  var item = myNodeList[i];
}
S.Serpooshan
fonte
0

Muito já foi dito, mas pensei que uma versão mais resumida da resposta com um exemplo para explicar as diferenças entre HTMLCollectione NodeListajudaria.

Tipos de nós em DOM

  • Existem 12 tipos de nós diferentes, que podem ter filhos de vários tipos de nós:

insira a descrição da imagem aqui

  • Podemos usar as três propriedades a seguir para inspecionar e perguntar sobre nós no DOM:

    • nodeType Propriedade
    • nodeName Propriedade
    • nodeValue Propriedade
  • A nodeTypepropriedade retorna o tipo de nó, como um número, do nó especificado.

    • Se o nó for um nó de elemento, a nodeTypepropriedade retornará 1 .
    • Se o nó for um nó de atributo, a nodeTypepropriedade retornará 2 .
    • Se o nó for um nó de texto, a nodeTypepropriedade retornará 3 .
    • Se o nó for um nó de comentário, a nodeTypepropriedade retornará 8 .
    • Esta propriedade é somente leitura.

HTMLCollection vs NodeList

insira a descrição da imagem aqui

Podemos entender as diferenças entre HTMLCollectione NodeListmais claramente com o exemplo a seguir. Por favor, tente verificar os resultados no console do seu próprio navegador para ter um melhor entendimento.

<ul>
  <li>foo</li>
  <li>bar</li>
  <li>bar</li>
</ul>
// retrieve element using querySelectorAll
const listItems_querySelector = document.querySelectorAll('li');
console.log('querySelector', listItems_querySelector);

// retrieve element using childNodes
const list  = document.querySelector('ul')
const listItems_childNodes = list.childNodes;
console.log('childNodes', listItems_childNodes);
const listItems_children = list.children;
console.log('children', listItems_children);

const listItems_getElementsByTagName = document.getElementsByTagName('li');
console.log('getElementsByTagName', listItems_getElementsByTagName);

console.log('*************************');
console.log('add one list item');
console.log('*************************');
list.appendChild(document.createElement('li'));

console.log('querySelector', listItems_querySelector);
console.log('childNodes', listItems_childNodes);
console.log('children', listItems_children);
console.log('getElementsByTagName', listItems_getElementsByTagName);

console.log('*************************');
console.log('add one more list item');
console.log('*************************');
listItems_getElementsByTagName[0].parentNode.appendChild(document.createElement('li'));

console.log('querySelector', listItems_querySelector);
console.log('childNodes', listItems_childNodes);
console.log('children', listItems_children);
console.log('getElementsByTagName', listItems_getElementsByTagName); 
Shraddha
fonte