[Перевод] В чём разница между узлом и элементом DOM?
При работе с DOM, кроме того, используется термин «элемент». Элементы очень похожи на узлы, но, всё же, это — не одно и то же. В чём же разница?
1. Узел DOM
Ключ к пониманию различия между узлом и элементом заключается в знании о том, что собой представляет узел.
Если рассматривать ситуацию в общих чертах, то оказывается, что DOM-документ включает в себя иерархию узлов. У каждого узла может быть родитель и (или) потомок.
Посмотрим на следующий HTML-документ:
My Page
My Page
Thank you for visiting my web page!
В документ входит следующая иерархия узлов:
DOM-представление документа
— это узел в дереве документа. У него есть два дочерних узла —
и
.
У есть три дочерних узла — комментарий
, заголовок
и абзац
. Родительским элементом узла
является узел
.
Теги в HTML-документе представляют узлы. Интересно то, что обычный текст — это тоже узел. Узел-абзац имеет потомка — текстовый узел
Thank you for visiting my web page!
.
▍Типы узлов
Как различать узлы разных типов? Ответ кроется в интерфейсе DOM, который носит имя Node. В частности — речь идёт о свойстве
Node.nodeType
.Это свойство может иметь одно из следующих значений, представляющих тип узла:
- Node.ELEMENT_NODE
- Node.ATTRIBUTE_NODE
- Node.TEXT_NODE
- Node.CDATA_SECTION_NODE
- Node.PROCESSING_INSTRUCTION_NODE
- Node.COMMENT_NODE
- Node.DOCUMENT_NODE
- Node.DOCUMENT_TYPE_NODE
- Node.DOCUMENT_FRAGMENT_NODE
- Node.NOTATION_NODE
Имена констант указывают на тип узла. Например,
Node.ELEMENT_NODE
представляет узел-элемент, Node.TEXT_NODE
— это текстовый узел, Node.DOCUMENT_NODE
— это узел-документ и так далее.Например, давайте выберем узел-абзац и посмотрим на его свойство nodeType
:
const paragraph = document.querySelector('p');
paragraph.nodeType === Node.ELEMENT_NODE; // => true
Свойство
paragraph.nodeType
, как и ожидалось, содержит значение Node.ELEMENT_NODE
, которое указывает на то, что абзац — это элемент.В абзаце, кроме того, имеется текстовый узел:
const paragraph = document.querySelector('p');
const firstChild = paragraph.childNodes[0];
firstChild.nodeType === Node.TEXT_NODE; // => true
Есть тип узла, который представляет всё дерево узлов документа. Это —
Node.DOCUMENT_NODE
: document.nodeType === Node.DOCUMENT_NODE; // => true
2. Элемент DOM
После того, как мы разобрались с тем, что такое узел DOM, пришло время поговорить том, чем различаются узлы и элементы DOM.
Если вы как следует вникли в сущность термина «узел», то вам уже всё должно быть понятно. Элемент — это узел особого типа — Node.ELEMENT_NODE
. Это — такой же тип узла, как и другие, представляющие весь документ, комментарии, тексты и прочие узлы DOM.
Если говорить простыми словами, то элемент — это узел, который объявлен с использованием тега в HTML-документе. ,
,
, ,
,
— это всё элементы, так как они представлены тегами.
А вот сам документ, комментарий, текст — это не элементы, так как они не представлены соответствующими тегами:
Thank you for visiting my web page!
В DOM-API JavaScript конструктор узла — это
Node
, а HTMLElement
— это конструктор элемента. Абзац, хотя это и узел DOM, является ещё и элементом, соответствующий объект является и экземпляром Node
, и экземпляром HTMLElement
: const paragraph = document.querySelector('p');
paragraph instanceof Node; // => true
paragraph instanceof HTMLElement; // => true
Если говорить простыми словами, элемент — это подтип узла — так же как кошка — подтип животного.
3. Свойства DOM: узлы и элементы
Помимо различения узлов и элементов нужно ещё различать свойства DOM, которые содержат исключительно узлы или исключительно элементы.
Следующие свойства могут содержать либо узел (Node
), либо коллекцию узлов (NodeList
):
node.parentNode; // Node или null
node.firstChild; // Node или null
node.lastChild; // Node или null
node.childNodes; // NodeList
А вот следующие свойства могут содержать либо элементы (
HTMLElement
), либо коллекции элементов (HTMLCollection
): node.parentElement; // HTMLElement или null
node.children; // HTMLCollection
Так как и свойство
node.childNodes
, и свойство node.children
возвращает коллекцию сущностей-потомков, возникает вопрос о том, почему существуют оба этих свойства. На самом деле это — хороший вопрос! Рассмотрим следующий элемент-абзац, содержащий какой-то текст:
Thank you for visiting my web page!
Откройте этот демонстрационный пример и посмотрите на свойства
childNodes
и children
узла-абзаца: const paragraph = document.querySelector('p');
paragraph.childNodes; // NodeList: [HTMLElement, Text]
paragraph.children; // HTMLCollection: [HTMLElement]
Коллекция
paragraph.childNodes
содержит 2 узла: текст, оформленный полужирным шрифтом с помощью тега
(Thank you
), и текстовый узел (for visiting my web page!
).Но в коллекции paragraph.children
имеется лишь 1 элемент, представленный тегом (
Thank you
).
Так как свойство paragraph.children
содержит только элементы, текстовый узел в него не включён. Произошло это из-за того, что с точки зрения системы это — текст (Node.TEXT_NODE
), а не элемент (Node.ELEMENT_NODE
).
То, что у нас есть и node.childNodes
, и node.children
, позволяет нам выбирать именно ту коллекцию элементов-потомков некоего узла DOM, с которой нужно работать. Это может быть либо коллекция, содержащая все узлы-потомки, либо только те узлы-потомки, которые являются элементами.
4. Итоги
Документ DOM — это иерархическая коллекция узлов. У каждого узла могут быть родители и (или) потомки.
Отличие между узлами и элементами DOM становится очевидным в том случае, если есть понимание того, что такое узел.
У узлов имеется свойство, указывающее на их тип. Один из этих типов соответствует элементам DOM. Элементы представлены тегами в HTML-документе.
Сталкивались ли вы со сложностями, касающимися различения узлов и элементов DOM?