Різниця між HTMLCollection, NodeLists та масивами об'єктів


94

Я завжди плутався між HTMLCollections, об’єктами та масивами, коли справа стосується DOM. Наприклад...

  1. У чому різниця між document.getElementsByTagName("td")і $("td")?
  2. $("#myTable")і $("td")є об’єктами (об’єктами jQuery). Чому console.log також відображає масив елементів DOM поруч з ними, і чи не є це об’єктами і не масивом?
  3. Що таке невловимий "NodeLists" і як мені вибрати його?

Будь ласка, надайте будь-яке тлумачення наведеного нижче сценарію.

Дякую

[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'). (b) Принципова відмінність полягає в тому, що jQuery працює зі своїм власним типом об'єкта, який містить, серед іншого, нумеровану колекцію елементів HTML; ця колекція не є нічим із наведеного, а об’єкт jQuery по суті є обгорткою навколо справжніх елементів DOM.
Маннго,

Відповіді:


113

Спочатку поясню різницю між NodeListі HTMLCollection.

Обидва інтерфейси - це колекції вузлів DOM. Вони відрізняються між собою методами, які вони надають, і типом вузлів, які вони можуть містити. Хоча a NodeListможе містити будь-який тип вузла, an HTMLCollectionповинен містити лише вузли Element.
An HTMLCollectionзабезпечує ті самі методи, що NodeListі a, а також метод, який називається 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властивість (майте на увазі, що масиви - це просто самі об'єкти). Браузери, як правило, відображають масиви та схожі на них об'єкти особливим чином, наприклад[ ... , ... , ... ] .

Що таке невловимий "NodeLists" і як мені вибрати його?

Дивіться першу частину моєї відповіді. Ви не можете вибрати NodeList s, вони є результатом відбору.

Наскільки я знаю, навіть немає способу NodeListпрограмного створення s (тобто створення порожнього та додавання вузлів пізніше), вони повертаються лише деякими методами / властивостями DOM.


2
@ user1032531: Ну, якщо ви внесете будь-які зміни в один із вибраних елементів DOM (наприклад, додаєте дочірній елемент), тоді ви, звичайно, побачите зміни, оскільки це один і той же елемент DOM. Але, якщо припустити, що ви вибрали всі tdелементи, додавання нового tdелемента пізніше не оновить виділення автоматично, щоб містити новий елемент.
Фелікс Клінг,

2
@FelixKling: Ви повинні зазначити , що не всі NodeLists знаходяться під напругою.
Бергі,

2
Я би хотів, щоб усі вони були масивами
SuperUberDuper

7
Здається також, що методи "ключі", "записи" та "forEach" присутні в NodeList, але відсутні в HTMLCollection
Кшиштоф

2
@KrzysztofGrzybek Це правильно, і це дуже дратує. Чому, чорт вазьми, один з них має, .forEach()а інший ні?
Robo Robok

30

0. У чому різниця між an HTMLCollectionі a NodeList?

Ось кілька визначень для вас.

Специфікація DOM рівня 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 (A 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. Що таке невловимий "NodeLists" і як мені вибрати його?

Ви отримували їх у своєму коді, getElementsByClassNameі getElementsByTagNameобидва повертають NodeLists

NodeList


Як ви показали DOM у своїй 3-й відповіді? Дякую!
user1032531,

@ user1032531, тобто інструменти розробника Chrome. До речі, я оновив початок відповіді.
Даніель Іммс,

Журнал, подібний до масиву, в основному є результатом lengthвластивості, а не числових імен властивостей. І до чого пов’язаний ваш приклад попередження рядка console.log?
Бергі,

Це показувало, як ви можете мати числові властивості об’єктів. Я намагаюся наголосити на фактах, що вони є об'єктами, а не масивами.
Даніель Іммс,

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,

Дякую @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 - це лише один тип Nodes:

Вузол << успадкування елемента HTMLE

Вузол може бути декількох типів . Найбільш важливі з них:

  • елемент (1): вузол елемента, такий як <p>або <div>.
  • атрибут (2): атрибут елемента. Атрибути елемента більше не реалізують інтерфейс Node у специфікації 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, яке можна використовувати для циклу по їх елементам. Не використовуйте для ... в або для кожного ... в для перерахування елементів у 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.