Różnica między HTMLCollection, NodeLists i tablicami obiektów

94

Zawsze mylono mnie między HTMLCollections, obiektami i tablicami, jeśli chodzi o DOM. Na przykład...

  1. Jaka jest różnica między document.getElementsByTagName("td")i $("td")?
  2. $("#myTable")i $("td")są obiektami (obiektami jQuery). Dlaczego console.log pokazuje również tablicę elementów DOM obok nich i czy nie są to obiekty ani tablica?
  3. O co chodzi w nieuchwytnych „NodeLists” i jak je wybrać?

Prosimy o podanie dowolnej interpretacji poniższego skryptu.

Dziękuję Ci

[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
źródło
Myślę, że mógłbym dodać następujące dla potomności. (a) We współczesnym JavaScript lepsze byłoby porównanie między document.querySelectorAll('td')i $('td'). (b) Podstawowa różnica polega na tym, że jQuery działa z własnym typem obiektu, który zawiera między innymi ponumerowaną kolekcję elementów HTML; ta kolekcja nie jest żadną z powyższych, a obiekt jQuery jest zasadniczo opakowaniem otaczającym prawdziwe elementy DOM.
Manngo

Odpowiedzi:

113

Najpierw wyjaśnię różnicę między NodeListi HTMLCollection.

Oba interfejsy są kolekcjami węzłów DOM. Różnią się metodami, które zapewniają i typem węzłów, które mogą zawierać. Podczas gdy NodeListmoże zawierać dowolny typ węzła, HTMLCollectionpowinien zawierać tylko węzły elementów.
An HTMLCollectionudostępnia te same metody co a NodeListi dodatkowo metodę o nazwie namedItem.

Kolekcje są zawsze używane, gdy trzeba zapewnić dostęp do wielu węzłów, np. Większość metod selektora (takich jak getElementsByTagName) zwraca wiele węzłów lub uzyskuje odwołanie do wszystkich elementów podrzędnych ( element.childNodes).

Aby uzyskać więcej informacji, zajrzyj do specyfikacji DOM4 - Kolekcje .

Jaka jest różnica między document.getElementsByTagName("td")i $("td")?

getElementsByTagNameto metoda interfejsu DOM. Akceptuje nazwę znacznika jako dane wejściowe i zwraca HTMLCollection(patrz specyfikacja DOM4 ).

$("td")to prawdopodobnie jQuery. Akceptuje dowolny prawidłowy selektor CSS / jQuery i zwraca obiekt jQuery.

Największą różnicą między standardowymi kolekcjami DOM a selekcjami jQuery jest to, że kolekcje DOM są zwykle aktywne (chociaż nie wszystkie metody zwracają kolekcję na żywo), tj. Wszelkie zmiany w DOM są odzwierciedlane w kolekcjach, jeśli mają na nie wpływ. Są jak widok drzewa DOM, podczas gdy wybory z jQuery są migawkami drzewa DOM w momencie wywołania funkcji.

Dlaczego console.log pokazuje również tablicę elementów DOM obok nich i czy nie są to obiekty ani tablica?

Obiekty jQuery są obiektami podobnymi do tablic , tj. mają właściwości numeryczne i lengthwłaściwość (pamiętaj, że tablice są same w sobie obiektami). Przeglądarki mają tendencję do wyświetlania tablic i obiektów podobnych do tablic w specjalny sposób, na przykład [ ... , ... , ... ].

O co chodzi w nieuchwytnych „NodeLists” i jak je wybrać?

Zobacz pierwszą część mojej odpowiedzi. Nie możesz wybrać NodeList s, są one wynikiem selekcji.

O ile wiem, nie ma nawet sposobu na NodeListprogramowe tworzenie s (tj. Tworzenie pustego i dodawanie węzłów później), są one zwracane tylko przez niektóre metody / właściwości DOM.

Felix Kling
źródło
2
@ user1032531: Cóż, jeśli dokonasz jakiejkolwiek zmiany w jednym z wybranych elementów DOM (np. dodając dziecko), to oczywiście zobaczysz zmianę, ponieważ jest to jeden i ten sam element DOM. Ale zakładając, że wybrałeś wszystkie tdelementy, dodanie nowego tdelementu później nie zaktualizuje automatycznie wyboru, aby zawierał nowy element.
Felix Kling
2
@FelixKling: Należy wspomnieć, że nie wszystkie NodeLists są pod napięciem.
Bergi
2
Chciałbym, żeby wszystkie były tablicami
SuperUberDuper
7
Wygląda też na to, że metody "keys", "places" i "forEach" prezentuję w NodeList, ale brakuje ich w HTMLCollection
Krzysztof Grzybek
2
@KrzysztofGrzybek Zgadza się i to jest super irytujące. Dlaczego do cholery jeden z nich ma, .forEach()a drugi nie?
Robo Robok
30

0. Jaka jest różnica między HTMLCollectiona a NodeList?

Oto kilka definicji dla Ciebie.

Specyfikacja DOM Level 1 - różne definicje obiektów :

Interfejs HTMLCollection

HTMLCollection to lista węzłów. Dostęp do pojedynczego węzła można uzyskać za pomocą indeksu porządkowego lub nazwy lub atrybutów identyfikatora węzła. Uwaga: Zakłada się, że kolekcje w HTML DOM są aktywne, co oznacza, że ​​są automatycznie aktualizowane po zmianie dokumentu źródłowego.

Specyfikacja DOM Level 3 - NodeList

Interfejs NodeList

Interfejs NodeList zapewnia abstrakcję uporządkowanej kolekcji węzłów, bez definiowania lub ograniczania sposobu implementacji tej kolekcji. Obiekty NodeList w DOM są aktywne.

Elementy w NodeList są dostępne za pośrednictwem indeksu całkowitego, zaczynając od 0.

Więc oba mogą zawierać aktualne dane, co oznacza, że ​​DOM zaktualizuje się, gdy zrobią to ich wartości. Zawierają również inny zestaw funkcji.

Jeśli sprawdzisz konsolę, jeśli uruchomisz skrypty, zauważysz, że tableelement DOM zawiera zarówno a, jak childNodes NodeList[2]i a children HTMLCollection[1]. Dlaczego się różnią? Ponieważ HTMLCollectionmoże zawierać tylko węzły elementów, NodeList zawiera również węzeł tekstowy.

wprowadź opis obrazu tutaj

1. Jaka jest różnica między document.getElementsByTagName("td")i $("td")?

document.getElementsByTagName("td")Zwraca tablicę elementów DOM (a NodeList), $("td")nazywa się obiekt jQuery, który posiada elementy z document.getElementsByTagName("td")jego właściwości 0, 1, 2, itd. Główną różnicą jest to, że obiekt jQuery jest trochę wolniej odzyskać, ale daje dostęp do wszystkich poręczny Funkcje jQuery.

2. $("#myTable")i $("td")są obiektami ( jQueryobiektami). Dlaczego console.logobok nich jest wyświetlana tablica elementów DOM i czy nie są to obiekty ani tablica?

Są to obiekty z ich właściwości 0, 1, 2itd zestaw do elementów DOM. Oto prosty przykład: jak to działa:

jsFiddle

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

3. O co chodzi w nieuchwytnych „NodeLists” i jak je wybrać?

Pobierasz je w swoim kodzie getElementsByClassNamei getElementsByTagNameoba zwracają NodeLists

NodeList

Daniel Imms
źródło
Jak wyświetliłeś DOM w swojej trzeciej odpowiedzi? Dzięki!
user1032531
@ user1032531, czyli narzędzia deweloperskie Chrome. Przy okazji zaktualizowałem początek odpowiedzi.
Daniel Imms
Rejestr przypominający tablicę jest głównie wynikiem lengthwłaściwości, a nie numerycznych nazw właściwości. A co ma wspólnego twój przykład z ostrzeżeniem łańcucha console.log?
Bergi
To pokazywało, jak można mieć właściwości numeryczne na obiektach. Próbuję podkreślić fakty, że są to obiekty, a nie tablice.
Daniel Imms,
9

Dodatkowa uwaga

Jaka jest różnica między HTMLCollection a NodeList?

HTMLCollection zawiera tylko węzły element ( znaczniki ) i NodeList zawiera wszystkie węzły .

Istnieją cztery typy węzłów:

  1. węzeł elementu
  2. węzeł atrybutów
  3. węzeł tekstowy
  4. węzeł komentarza

nodeTypes

Spacje wewnątrz elementów są traktowane jako tekst, a tekst jako węzły.

Rozważ następujące:

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

Biała przestrzeń: <ul id="myList"> <li>List item</li></ul>

Bez spacji: <ul id="myList"><li>List item</li></ul>

Różnica między HTMLCollection a NodeList

Słońce
źródło
2

$("td")jest rozszerzonym obiektem jQuery i posiada metody jQuery, zwraca obiekt jquery zawierający tablicę obiektów html. document.getElementsByTagName("td")jest surową metodą js i zwraca NodeList. Zobacz ten artykuł

karaxuna
źródło
Dzięki Karaxuna. Tak, przejrzałem ten artykuł. Nie wiem, czy to pomogło, ale zdecydowanie sprawiło, że zadałem więcej pytań :)
user1032531
Dzięki @karaxuna. Przydatny artykuł, bardzo dobrze wyjaśniony.
Giuseppe
0

Obiekty NodeList to kolekcje węzłów zwracane na przykład przez x. childNodes lub metoda document.querySelectorAll () . W niektórych przypadkach, NodeList jest na żywo , co oznacza, że zmiany w DOM automatycznie aktualizować kolekcję! Na przykład Node.childNodes jest aktywny:

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.

Ale w niektórych innych przypadkach NodeList jest statyczna , gdzie wszelkie zmiany w DOM nie wpływają na zawartość kolekcji. querySelectorAll () zwraca statyczną listę NodeList.

HTMLCollection jest na żywo i nakazał zbiór elementów (to jest automatycznie aktualizowany, gdy dokument będący podstawą ulega zmianie). Może to wynikać z właściwości, takich jak dzieci lub metody, takie jak document.getElementsByTagName () i może mieć tylko elementy HTMLElement jako ich elementy.

HTMLCollection ujawnia również swoich członków bezpośrednio jako właściwości według nazwy i indeksu:

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

HTMLElement to tylko jeden typ węzłów:

Dziedziczenie węzła << HTMLElement

Węzeł może mieć kilka typów . Najważniejsze z nich to:

  • element (1): Węzeł elementu, taki jak <p>lub <div>.
  • atrybut (2): atrybut elementu. Atrybuty elementu nie implementują już interfejsu Node w specyfikacji DOM4!
  • text (3): rzeczywisty tekst elementu lub atrybutu.
  • comment (8): węzeł komentarza.
  • document (9): węzeł dokumentu.

Tak więc dużą różnicą jest to, że HTMLCollection zawiera tylko elementy HTMLElements, ale NodeList zawiera również komentarze, tekst z odstępami (znaki powrotu karetki, spacje ...), itd. Sprawdź to jak w następującym fragmencie:

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>

Zarówno HTMLCollection, jak i NodeList zawierają właściwość length, której można użyć do zapętlenia ich elementów. Nie używaj for ... in lub for each ... in do wyliczania elementów w NodeLists, ponieważ będą one również wyliczać długość i właściwości elementu oraz powodować błędy, jeśli twój skrypt zakłada, że ​​ma do czynienia tylko z obiektami elementów. Ponadto firma for..in nie gwarantuje odwiedzenia nieruchomości w określonej kolejności.

for (var i = 0; i < myNodeList.length; i++) {
  var item = myNodeList[i];
}
S.Serpooshan
źródło
0

Tyle już powiedziano, ale pomogłaby bardziej podsumowana wersja odpowiedzi z przykładem wyjaśniającym różnice między HTMLCollectioni NodeList.

Rodzaje węzłów w DOM

  • Istnieje 12 różnych typów węzłów, które mogą mieć dzieci różnych typów węzłów:

wprowadź opis obrazu tutaj

  • Możemy użyć następujących trzech właściwości, aby sprawdzić i zapytać o węzły w DOM:

    • nodeType własność
    • nodeName własność
    • nodeValue własność
  • nodeTypeWłaściwość zwraca typ węzła, jak numer, z określonego węzła.

    • Jeśli węzeł jest węzłem elementu, nodeTypewłaściwość zwróci wartość 1 .
    • Jeśli węzeł jest węzłem atrybutu, nodeTypewłaściwość zwróci wartość 2 .
    • Jeśli węzeł jest węzłem tekstowym, nodeTypewłaściwość zwróci wartość 3 .
    • Jeśli węzeł jest węzłem komentarza, nodeTypewłaściwość zwróci wartość 8 .
    • Ta właściwość jest tylko do odczytu.

HTMLCollection a NodeList

wprowadź opis obrazu tutaj

Możemy lepiej zrozumieć różnice między HTMLCollectioni NodeListna poniższym przykładzie. Spróbuj sprawdzić wyniki we własnej konsoli przeglądarki, aby lepiej je zrozumieć.

<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
źródło