Разница между HTMLCollection, NodeLists и массивами объектов


94

Когда дело касается DOM, меня всегда путали между HTMLCollections, объектами и массивами. Например...

  1. В чем разница между document.getElementsByTagName("td")и $("td")?
  2. $("#myTable")и $("td")являются объектами (объектами jQuery). Почему console.log также показывает массив элементов DOM рядом с ними, и не являются ли они объектами и не массивом?
  3. Что такое неуловимые "списки узлов" и как их выбрать?

Также предоставьте любую интерпретацию приведенного ниже сценария.

Спасибо

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

Думаю, я мог бы добавить следующее для потомков. (а) В современном JavaScript лучше сравнить document.querySelectorAll('td')и $('td'). (б) Основное отличие состоит в том, что jQuery работает со своим собственным типом объекта, который, помимо прочего, содержит пронумерованный набор элементов HTML; эта коллекция не соответствует ни одному из вышеперечисленных, а объект jQuery по сути является оболочкой вокруг настоящих элементов DOM.
Manngo

Ответы:


113

Сначала я объясню разницу между NodeListи HTMLCollection.

Оба интерфейса представляют собой коллекции узлов DOM. Они различаются предоставляемыми ими методами и типом узлов, которые могут содержать. Хотя a NodeListможет содержать любой тип узла, HTMLCollectionпредполагается, что он содержит только узлы Element.
An HTMLCollectionпредоставляет те же методы, что и a, NodeListи дополнительно вызываемый метод namedItem.

Коллекции всегда используются, когда доступ должен быть предоставлен нескольким узлам, например, большинство методов селектора (таких как getElementsByTagName) возвращают несколько узлов или получают ссылку на всех дочерних узлов ( element.childNodes).

Для получения дополнительной информации ознакомьтесь со спецификацией DOM4 - Коллекции .

В чем разница между document.getElementsByTagName("td")и $("td")?

getElementsByTagNameэто метод интерфейса DOM. Он принимает имя тега в качестве входных данных и возвращает HTMLCollection(см. Спецификацию DOM4 ).

$("td")предположительно jQuery. Он принимает любой допустимый селектор CSS / jQuery и возвращает объект jQuery.

Самая большая разница между стандартными коллекциями DOM и выбором jQuery состоит в том, что коллекции DOM обычно являются живыми (хотя не все методы возвращают живую коллекцию), т.е. любые изменения в DOM отражаются в коллекциях, если они затронуты. Они похожи на представление дерева DOM, тогда как выбор jQuery - это снимки дерева DOM в момент вызова функции.

Почему console.log также показывает массив элементов DOM рядом с ними, и не являются ли они объектами и не массивом?

Объекты jQuery являются объектами, подобными массивам , т.е. они имеют числовые свойства и lengthсвойство (имейте в виду, что массивы сами по себе являются просто объектами). Браузеры имеют тенденцию отображать массивы и подобные массиву объекты особым образом, например [ ... , ... , ... ].

Что такое неуловимые "списки узлов" и как их выбрать?

См. Первую часть моего ответа. Вы не можете выбрать NodeList s, они являются результатом выбора.

Насколько я знаю, нет даже способа создать NodeLists программно (т.е. создать пустой и добавить узлы позже), они возвращаются только некоторыми методами / свойствами DOM.


2
@ user1032531: Что ж, если вы внесете какие-либо изменения в один из выбранных элементов DOM (например, добавите дочерний элемент), то вы, конечно же, увидите это изменение, поскольку это один и тот же элемент DOM. Но, предполагая, что вы выбрали все tdэлементы, добавление нового tdэлемента позже не приведет к автоматическому обновлению выделения, чтобы содержать новый элемент.
Феликс Клинг

2
@FelixKling: Вы должны отметить , что не все NodeLists находятся под напряжением.
Bergi

2
Хотел бы я, чтобы все они были массивами
SuperUberDuper

7
Также кажется, что методы «ключи», «записи» и «forEach» я присутствую в NodeList, но отсутствуют в HTMLCollection
Кшиштоф Гржибек

2
@KrzysztofGrzybek Верно, и это очень раздражает. Какого черта у одного есть, .forEach()а у другого нет?
Robo Robok,

30

0. В чем разница между an HTMLCollectionи a NodeList?

Вот вам несколько определений.

Спецификация DOM Level 1 - Разные определения объектов :

Интерфейс HTMLCollection

HTMLCollection - это список узлов. К отдельному узлу можно получить доступ либо по порядковому индексу, либо по имени или атрибутам идентификатора узла. Примечание. Коллекции в HTML DOM считаются живыми, что означает, что они автоматически обновляются при изменении базового документа.

Спецификация DOM уровня 3 - NodeList

Интерфейс NodeList

Интерфейс NodeList обеспечивает абстракцию упорядоченной коллекции узлов, не определяя и не ограничивая способ реализации этой коллекции. Объекты NodeList в DOM активны.

Элементы в NodeList доступны через интегральный индекс, начиная с 0.

Таким образом, они оба могут содержать данные в реальном времени, что означает, что DOM будет обновляться, когда их значения обновятся. Также они содержат другой набор функций.

Если вы проверите консоль и запустите свои скрипты, вы заметите, что tableэлемент DOM содержит как a, так childNodes NodeList[2]и a children HTMLCollection[1]. Почему они разные? Поскольку HTMLCollectionможет содержать только узлы элементов, NodeList также содержит текстовый узел.

введите описание изображения здесь

1. В чем разница между document.getElementsByTagName("td")и $("td")?

document.getElementsByTagName("td")возвращает массив элементов DOM (а NodeList), $("td")называется объект JQuery , который имеет элементы из document.getElementsByTagName("td")на его свойств 0, 1, 2и т.д. Основное отличие состоит в том , что объект JQuery немного медленнее , чтобы получить , но дает доступ ко всем удобно Функции jQuery.

2. $("#myTable")и $("td")являются объектами ( jQueryобъектами). Почему console.logрядом с ними также отображается массив элементов DOM, и они не являются объектами и не массивом?

Это объекты с их свойствами 0, 1, 2и т.д. набор к элементам DOM. Вот простой пример: как это работает:

jsFiddle

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

3. Что такое неуловимые «списки узлов» и как их выбрать?

Вы получали их в своем коде, getElementsByClassNameи getElementsByTagNameоба возвращают NodeLists

NodeList


Как вы отобразили DOM в своем третьем ответе? Благодарность!
user1032531 02

@ user1032531 - инструменты разработчика Chrome. Кстати, я обновил начало ответа.
Дэниел Иммс

Журнал, подобный массиву, в основном является результатом lengthсвойства, а не числовых имен свойств. И какое отношение имеет ваш пример с предупреждением о строке console.log?
Bergi

Это показало, как можно иметь числовые свойства для объектов. Я пытаюсь подчеркнуть тот факт, что это объекты, а не массивы.
Дэниел Иммс 02

9

Дополнительное примечание

В чем разница между HTMLCollection и NodeList?

HTMLCollection содержит только узлы элементов ( тегов ) и NodeList содержит все узлы .

Есть четыре типа узлов:

  1. узел элемента
  2. узел атрибута
  3. текстовый узел
  4. узел комментариев

nodeTypes

Пробелы внутри элементов считаются текстом, а текст - узлами.

Обратите внимание на следующее:

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

Пробелы: <ul id="myList"> <li>List item</li></ul>

Без пробелов: <ul id="myList"><li>List item</li></ul>

Разница между HTMLCollection и NodeList


2

$("td")является расширенным объектом jQuery и имеет методы jQuery, он возвращает объект jquery, содержащий массив объектов html. document.getElementsByTagName("td")является необработанным методом js и возвращает NodeList. См. Эту статью


Спасибо Караксуна. Да, я читал эту статью. Не знаю, помогло ли это, но определенно заставило меня задать больше вопросов :)
user1032531 02

Спасибо @karaxuna. Полезная статья, очень хорошо объясненная.
Джузеппе

0

В Nodelist объекты коллекция узла, возвращаемая, например, х. childNodes или метод document.querySelectorAll () . В некоторых случаях NodeList является живым , что означает , что изменения в DOM автоматически обновлять коллекцию! Например, Node.childNodes активен:

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.

Но в некоторых других случаях NodeList статичен , и любые изменения в DOM не влияют на содержимое коллекции. querySelectorAll () возвращает статический NodeList.

HTMLCollection является живым и упорядоченным набором элементов (она автоматически обновляется , когда основной документ изменен). Это может быть результатом свойств, таких как дочерние элементы, или методов, таких как document.getElementsByTagName () , и может иметь только HTMLElement в качестве своих элементов.

HTMLCollection также предоставляет свои члены напрямую как свойства по имени и индексу:

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

HTMLElement - это всего лишь один из типов узлов:

Узел << Наследование HTMLElement

Узел может быть нескольких типов . Наиболее важные из них следующие:

  • element (1): узел элемента, например <p>или <div>.
  • attribute (2): Атрибут элемента. Атрибуты элемента больше не реализуют интерфейс узла в спецификации DOM4!
  • text (3): Фактический текст элемента или атрибута.
  • comment (8): узел комментария.
  • документ (9): узел документа.

Итак, большая разница в том, что HTMLCollection содержит только HTMLElements, но NodeList также содержит комментарии, пробелы (символы возврата каретки, пробелы ...) и т.д. Проверьте это, как показано в следующем фрагменте:

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, и NodeList содержат свойство length, которое вы можете использовать для циклического перебора их элементов. Не используйте for ... in или for each ... in для перечисления элементов в NodeLists, поскольку они также будут перечислять его длину и свойства элемента и вызывать ошибки, если ваш сценарий предполагает, что он имеет дело только с объектами элементов. Кроме того, for..in не гарантируется посещение объектов в каком-либо определенном порядке.

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

0

Уже так много сказано, но подумал, что поможет более обобщенная версия ответа с примером, объясняющим различия между HTMLCollectionи NodeList.

Типы узлов в DOM

  • Существует 12 различных типов узлов, у которых могут быть дочерние узлы разных типов:

введите описание изображения здесь

  • Мы можем использовать следующие три свойства для проверки и запроса узлов в DOM:

    • nodeType Свойство
    • nodeName Свойство
    • nodeValue Свойство
  • nodeTypeСвойство возвращает тип узла, как число, указанного узла.

    • Если узел является узлом элемента, nodeTypeсвойство вернет 1 .
    • Если узел является узлом атрибута, nodeTypeсвойство вернет 2 .
    • Если узел является текстовым узлом, nodeTypeсвойство вернет 3 .
    • Если узел является узлом комментария, nodeTypeсвойство вернет 8 .
    • Это свойство доступно только для чтения.

HTMLCollection против NodeList

введите описание изображения здесь

Мы можем более четко понять различия между HTMLCollectionи NodeListна следующем примере. Пожалуйста, попробуйте проверить выходные данные в консоли вашего собственного браузера, чтобы лучше понять.

<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); 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.