Coleção Javascript de objetos DOM - por que não consigo reverter com Array.reverse()?
-
09-06-2019 - |
Pergunta
Qual poderia ser o problema em reverter a matriz de objetos DOM como no código a seguir:
var imagesArr = new Array();
imagesArr = document.getElementById("myDivHolderId").getElementsByTagName("img");
imagesArr.reverse();
No Firefox 3, quando eu chamo o reverse()
método, o script para de ser executado e mostra o seguinte erro no console da Web Developer Toolbar:
imagesArr.reverse is not a function
O imagesArr
variável pode ser iterada com um loop for e elementos como imagesArr[i]
pode ser acessado, então por que não é visto como um array ao chamar o reverse()
método?
Solução
Porque getElementsByTag name na verdade retorna uma estrutura NodeList.Possui matriz semelhante, como propriedades de indexação, por conveniência sintática, mas é não uma matriz.Por exemplo, o conjunto de entradas é constantemente atualizado de forma dinâmica - se você adicionar uma nova tag img em myDivHolderId, ela aparecerá automaticamente em imagesArr.
Ver http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-536297177 para mais.
Outras dicas
getElementsByTag()
retorna um NodeList em vez de um Array.Você pode converter um NodeList em um Array, mas observe que o array será outro objeto, portanto, revertê-lo não afetará a posição dos nós DOM.
var listNodes = document.getElementById("myDivHolderId").getElementsByTagName("img");
var arrayNodes = Array.slice.call(listNodes, 0);
arrayNodes.reverse();
Para alterar a posição, você terá que remover os nós DOM e adicioná-los novamente na posição correta.
Array.prototype.slice.call(arrayLike, 0)
é uma ótima maneira de converter um array em um array, mas se você estiver usando uma biblioteca JavaScript, ele pode fornecer uma maneira ainda melhor/mais rápida de fazer isso.Por exemplo, jQuery tem $.makeArray(arrayLike)
.
Você também pode usar os métodos Array diretamente no NodeList:
Array.prototype.reverse.call(listNodes);
getElementsByTag()
retorna um NodeList em vez de um Array.Você precisa converter o NodeList em um array e depois revertê-lo.
var imagesArr = [].slice.call(document.getElementById("myDivHolderId").getElementsByTagName("img"), 0).reverse();
Eu sei que esta pergunta é antiga, mas acho que precisa de um pouco de esclarecimento, pois algumas das respostas aqui estão desatualizadas, pois o W3C mudou a definição e, consequentemente, o valor de retorno desses métodos getElementsByTagName()
e getElementsByClassName()
Esses métodos no momento em que escrevi esta resposta retornar um objeto - vazio ou não - do tipo HTMLCollection
e não NodeList
.
É como a diferença entre as propriedades children
que retorna um objeto do tipo HTMLCollection
já que é composto apenas de elementos e excluindo nós de texto ou comentários, e childNodes
que retorna um objeto do tipo NodeList
já que também pode conter outros tipos de nós, como texto e comentários.
Observação:Eu iria pela tangente aqui e expressaria minha falta de compreensão sobre o porquê querySelectorAll()
método atualmente retorna um NodeList
e não um HTMLCollection
uma vez que funciona exclusivamente em nós de elementos do documento e nada mais.
Provavelmente tem algo a ver com a cobertura potencial de outros tipos de nós no futuro e eles optaram por uma solução mais preparada para o futuro, quem sabe?:)
EDITAR:Acho que entendi a razão por trás desta decisão de optar por um NodeList
e não um HTMLCollection
para o querySelectorAll()
.
Desde que eles construíram HTMLCollection
ser exclusiva e inteiramente ao vivo e como esse método não precisa dessa funcionalidade ao vivo, eles decidiram por um NodeList
implementação, em vez disso, para melhor servir o seu propósito de forma económica e eficiente.
Sua primeira linha é irrelevante, pois não força a atribuição à variável, o javascript funciona ao contrário.imagesArr, não é do tipo Array(), é qualquer que seja o tipo de retorno de getElementsByTagName("img").Neste caso, é um HtmlCollection no Firefox 3.
Os únicos métodos neste objeto são os indexadores e o comprimento.Para trabalhar ao contrário, basta iterar para trás.