3.4. DOM — объектная модель документа
                    DOM была придумана создателями браузеров. Консорциум World Wide Web Consortium (W3C) стандартизировал DOM как единую спецификацию.
W3C определяет DOM как «интерфейс, не зависящий от платформы и языка, который позволяет программам и сценариям динамически получать доступ к содержимому и структуре документов и обновлять их». То есть, данная модель не предоставляет конкретную реализацию, а лишь описывает объекты, свойства, методы.
Концепция DOM реализована с разной степенью поддержки во всех основных браузерах. С помощью объектной модели документа можно создавать документы, перемещаться по их структуре, а также добавлять, изменять или удалять элементы и содержимое.
Когда пользователь запрашивает определенную веб-страницу, механизм рендеринга начинает получать HTML, CSS и JS-файлы запрошенной веб-страницы через сетевой уровень. После получения содержимого страницы, HTML и CSS-файлы анализируются по частям. Узлы DOM создаются для формирования дерева DOM и дерева CSSOM.
Дерево визуализации создается путем объединения деревьев DOM и CSSOM. Дерево визуализации содержит как информацию о порядке элементов, так и информацию об их стиле. На этом этапе каждому узлу присваиваются специальные координаты, чтобы гарантировать, что каждый элемент отображается в одном и том же положении на экране. После чего выполняется обход дерева визуализации, и каждый узел, упомянутый в дереве, отображается на экране.
- Содержание:
 - 1. Введение в DOM
 - 2. Интерфейсы и узлы DOM
 - 3. Свойства узлов
 - 3.1. Определение типа и имени узла: свойства nodeName и nodeType
 - 3.2. Получение значения узла: свойство nodeValue
 - 3.3. Отношения между узлами
 - 3.3.1. Свойство childNodes
 - 3.3.2. Свойство parentNode
 - 3.3.3. Свойства previousSibling и nextSibling
 - 3.3.4. Свойства firstChild и lastChild
 - 3.3.5. Свойство parentElement
 - 3.3.6. Свойство ownerDocument
 - 3.4. Другие свойства узлов: baseURI, isConnected и textContent
 - 4. Манипуляции узлами
 - 4.1. Создание новых узлов
 - 4.1.1. Метод appendChild()
 - 4.1.2. Метод cloneNode()
 - 4.1.3. Метод insertBefore()
 - 4.1.4. Метод replaceChild()
 - 4.1.5. Метод removeChild()
 - 4.2. Проверка позиции узла в дереве DOM: методы compareDocumentPosition() и contains()
 - 4.3. Определение идентичности узлов с помощью метода isEqualNode()
 - 4.4. Определение отношений между узлами
 - 5. Пространства имен XML: методы ookupNamespaceURI(), isDefaultNamespace() и lookupPrefix()
 - 6. Объединение родственных текстовых узлов в один с помощью метода normalize()
 
1. Введение в DOM
DOM — это API для HTML и XML-документов. API расшифровывается как интерфейс прикладного программирования, который можно определить как совокупность способов связи между различными компонентами программного обеспечения. Другими словами, API позволяет одной программе взаимодействовать с другой.
Спецификация DOM определяет набор интерфейсов для доступа и управления объектами HTML и XML-документов. Интерфейсы являются абстракцией, средствами определения способа доступа и управления внутренними представлениями документа в приложении.
Согласно терминологии W3C DOM, каждый документ представлен в виде дерева, а каждый автономный элемент или текстовый блок известен как узел — фундаментальный строительный блок. Термин «узел» происходит из сети, где он используется для обозначения точки подключения, и сама сеть представляет собой набор узлов. Узлы имеют отношения родитель-потомок, когда один контейнер содержит другой. Узел — это общее имя для объекта любого типа в иерархии DOM.
Когда происходит загрузка соответствующей страницы, в памяти браузера реализуется поддержка структуры объектов, сгенерированных согласно использованным в документе HTML-тегам. У каждого узла есть родительский узел (за исключением корневого узла document) и любое количество дочерних узлов. Одни типы узлов могут иметь дочерние узлы различных типов, другие являются так называемыми листовыми узлами, у которых не может дочерних узлов. Дерево состоит из узлов, но только некоторые из них являются HTML-элементами.
Узлы не представляют структуру данных, они представляют объекты, которые имеют функции и идентичность. В объектно-ориентированных языках программирования данные инкапсулируются в объекты, которые скрывают данные, защищая их от прямых внешних манипуляций. Функции, связанные с этими объектами, определяют, как ими можно манипулировать.
2. Интерфейсы и узлы DOM
Ядро DOM API состоит из Node, Element, Document и других относительно универсальных интерфейсов. Стандарт DOM также включает интерфейсы, специфичные как для HTML-документов, так и тегов многих HTML-элементов. Эти интерфейсы, например, HTMLBodyElement, HTMLTitleElement, обычно определяют набор свойств, отражающих атрибуты тега, которые обеспечивают удобный доступ к значениям атрибутов.
Базовый интерфейс, от которого наследуются все интерфейсы HTML-элементов и который должен использоваться элементами, не имеющими дополнительных атрибутов, — это интерфейс HTMLElement.
| Элемент(ы) | Интерфейс(ы) | 
|---|---|
| <a> | HTMLAnchorElement : HTMLElement | 
| <abbr> | HTMLElement | 
| <address> | HTMLElement | 
| <area> | HTMLAreaElement : HTMLElement | 
| <article> | HTMLElement | 
| <aside> | HTMLElement | 
| <audio> | HTMLAudioElement : HTMLMediaElement : HTMLElement | 
| <b> | HTMLElement | 
| <base> | HTMLBaseElement : HTMLElement | 
| <bdi> | HTMLElement | 
| <bdo> | HTMLElement | 
| <blockquote> | HTMLQuoteElement : HTMLElement | 
| <body> | HTMLBodyElement : HTMLElement | 
| <br> | HTMLBRElement : HTMLElement | 
| <button> | HTMLButtonElement : HTMLElement | 
| <canvas> | HTMLCanvasElement : HTMLElement | 
| <caption> | HTMLTableCaptionElement : HTMLElement | 
| <cite> | HTMLElement | 
| <code> | HTMLElement | 
| <col> | HTMLTableColElement : HTMLElement | 
| <colgroup> | HTMLTableColElement : HTMLElement | 
| <data> | HTMLDataElement : HTMLElement | 
| <datalist> | HTMLDataListElement : HTMLElement | 
| <dd> | HTMLElement | 
| <del> | HTMLModElement : HTMLElement | 
| <details> | HTMLDetailsElement : HTMLElement | 
| <dfn> | HTMLElement | 
| <dialog> | HTMLDialogElement : HTMLElement | 
| <div> | HTMLDivElement : HTMLElement | 
| <dl> | HTMLDListElement : HTMLElement | 
| <dt> | HTMLElement | 
| <em> | HTMLElement | 
| <embed> | HTMLEmbedElement : HTMLElement | 
| <fieldset> | HTMLFieldSetElement : HTMLElement | 
| <figcaption> | HTMLElement | 
| <figure> | HTMLElement | 
| <footer> | HTMLElement | 
| <form> | HTMLFormElement : HTMLElement | 
| <h1> — <h6> | HTMLHeadingElement : HTMLElement | 
| <head> | HTMLHeadElement : HTMLElement | 
| <header> | HTMLElement | 
| <hgroup> | HTMLElement | 
| <hr> | HTMLHRElement : HTMLElement | 
| <html> | HTMLHtmlElement : HTMLElement | 
| <i> | HTMLElement | 
| <iframe> | HTMLIFrameElemen : HTMLElement | 
| <img> | HTMLImageElement : HTMLElement | 
| <input> | HTMLInputElement : HTMLElement | 
| <ins> | HTMLModElement : HTMLElement | 
| <kbd> | HTMLElement | 
| <label> | HTMLLabelElement : HTMLElement | 
| <legend> | HTMLLegendElement : HTMLElement | 
| <li> | HTMLLIElement : HTMLElement | 
| <link> | HTMLLinkElement : HTMLElement | 
| <main> | HTMLElement | 
| <map> | HTMLMapElement : HTMLElement | 
| <mark> | HTMLElement | 
| <menu> | HTMLMenuElement : HTMLElement | 
| <meta> | HTMLMetaElement : HTMLElement | 
| <meter> | HTMLMeterElement : HTMLElement | 
| <nav> | HTMLElement | 
| <noscript> | HTMLElement | 
| <object> | HTMLObjectElement : HTMLElement | 
| <ol> | HTMLOListElement : HTMLElement | 
| <optgroup> | HTMLOptGroupElement : HTMLElement | 
| <option> | HTMLOptionElement : HTMLElement | 
| <output> | HTMLOutputElement : HTMLElement | 
| <p> | HTMLParagraphElement : HTMLElement | 
| <param> | HTMLParamElement : HTMLElement | 
| <picture> | HTMLPictureElement : HTMLElement | 
| <pre> | HTMLPreElement : HTMLElement | 
| <progress> | HTMLProgressElement : HTMLElement | 
| <q> | HTMLQuoteElement : HTMLElement | 
| <rp> | HTMLElement | 
| <rt> | HTMLElement | 
| <ruby> | HTMLElement | 
| <s> | HTMLElement | 
| <samp> | HTMLElement | 
| <script> | HTMLScriptElement : HTMLElement | 
| <section> | HTMLElement | 
| <select> | HTMLSelectElement : HTMLElement | 
| <slot> | HTMLSlotElement : HTMLElement | 
| <small> | HTMLElement | 
| <source> | HTMLSourceElement : HTMLElement | 
| <span> | HTMLSpanElement : HTMLElement | 
| <strong> | HTMLElement | 
| <style> | HTMLStyleElement : HTMLElement | 
| <sub> | HTMLElement | 
| <summary> | HTMLElement | 
| <sup> | HTMLElement | 
| <table> | HTMLTableElement : HTMLElement | 
| <tbody> | HTMLTableSectionElement : HTMLElement | 
| <td> | HTMLTableCellElement : HTMLElement | 
| <template> | HTMLTemplateElement : HTMLElement | 
| <textarea> | HTMLTextAreaElement : HTMLElement | 
| <tfoot> | HTMLTableSectionElement : HTMLElement | 
| <th> | HTMLTableCellElement : HTMLElement | 
| <thead> | HTMLTableSectionElement : HTMLElement | 
| <time> | HTMLTimeElement : HTMLElement | 
| <title> | HTMLTitleElement : HTMLElement | 
| <tr> | HTMLTableRowElement : HTMLElement | 
| <track> | HTMLTrackElement : HTMLElement | 
| <u> | HTMLElement | 
| <ul> | HTMLUListElement : HTMLElement | 
| <var> | HTMLElement | 
| <video> | HTMLVideoElement : HTMLMediaElement : HTMLElement | 
| <wbr> | HTMLElement | 
Интерфейс Node (который в свою очередь реализует интерфейс EventTarget) является основным типом данных для всей объектной модели документа. Node представляет собой абстрактный интерфейс и не существует как узел. Он используется всеми узлами — Document, DocumentType, DocumentFragment, Element, Text, Attr, CDATASection, ProcessingInstruction и Comment.
Хотя все объекты, реализующие интерфейс Node, предоставляют методы для работы с потомками, не все объекты, реализующие интерфейс Node, могут иметь потомков (например, текстовые узлы).
3. Свойства узлов
Все объекты узлов, например, Element, Text и т.д., наследуют свойства и методы от интерфейса Node. Эти свойства и методы являются базовыми значениями и функциями для управления, проверки и обхода DOM.
Многие свойства DOM доступны только для чтения. Это означает, что их можно использовать для получения информации, но не для ее установки или обновления.
3.1. Определение типа и имени узла: свойства nodeName и nodeType
У объектов Node есть свойства идентификации, такие как nodeName и nodeType.
| Интерфейс | nodeType | Значение nodeName | 
|---|---|---|
| Element | Node.ELEMENT_NODE (1) | полное имя HTML-тега в верхнем регистре | 
| Attr | Node.ATTRIBUTE_NODE (2) | полное имя атрибута | 
| Text | Node.TEXT_NODE (3) | #text | 
| CDATASection | Node.CDATA_SECTION_NODE (4) | #cdata-section | 
| ProcessingInstruction | Node.PROCESSING_INSTRUCTION_NODE (7) | имя, определяющее приложение, для которого предназначена инструкция | 
| Comment | Node.COMMENT_NODE (8) | #comment | 
| Document | Node.DOCUMENT_NODE (9) | #document | 
| DocumentType | Node.DOCUMENT_TYPE_NODE (10) | название типа документа | 
| DocumentFragment | Node.DOCUMENT_FRAGMENT_NODE (11) | #document-fragment | 
<!DOCTYPE html>
<html lang="ru">
<body>
   <p class="example">Какой-то текст</a>
</body>
</html>
Свойство nodeName возвращает имя/название в виде строки, либо постоянное значение (которому предшествует символ #). Используется только для чтения.
console.log(document.doctype.nodeName)); // html
console.log(document.nodeName); // #document
console.log(document.body.nodeName); // BODY
console.log(document.createDocumentFragment().nodeName); // #document-fragment
console.log(document.querySelector('p').nodeName); // P
console.log(document.querySelector('p').firstChild.nodeName); // #text  
console.log(document.querySelector('p').nodeType === 1); // true
Свойство nodeType возвращает целочисленный идентификатор типа узла. Интерфейс Node содержит константы, которые соответствуют этим числам. Определение типа узла полезно в сценариях, когда перебирается неизвестный набор узлов. Определение типа узла, для которого вы можете написать сценарий, может быть очень удобным, если вы хотите знать, какие свойства и методы доступны для сценария узла.
console.log(document.doctype.nodeType); // 10
console.log(document.nodeType); // 9
console.log(document.createDocumentFragment().nodeType); // 11
console.log(document.querySelector('p').nodeType); // 1
console.log(document.querySelector('p').firstChild.nodeType);// 3
3.2. Получение значения узла: свойство nodeValue
Свойство nodeValue возвращает или устанавливает значение узла.
Для большинства типов узлов возвращает null и любой набор операций игнорируется. Для узлов типа TEXT_NODE, COMMENT_NODE, CDATA_SECTION_NODE и PROCESSING_INSTRUCTION_NODE, значение соответствует текстовым данным, содержащимся в объекте. Для узла ATTRIBUTE_NODE вернет значение атрибута.
Использование данного свойства полезно для извлечения текстовых строк из узлов Text и Comment.
console.log(document.doctype.nodeValue); // null
console.log(document.nodeValue); // null
console.log(document.createDocumentFragment().nodeValue); // null
console.log(document.querySelector('p').nodeValue); // null
console.log(document.querySelector('p').firstChild.nodeValue); // Какой-то текст
3.3. Отношения между узлами
Все узлы в документе имеют связи с другими узлами. Эти отношения описываются в терминах традиционных семейных отношений, как если бы дерево документа было генеалогическим древом.
<ul id="list">
   <li>Пункт 1</li>
   <li>Пункт 2</li>
   <li><a href="https://google.com">Пункт 3</a></li>
   <li>Пункт 4</li>
</ul>
3.3.1. Свойство childNodes
Каждый узел имеет свойство childNodes, которое извлекает все дочерние узлы объекта и сохраняет их возвращает живой NodeList, содержащий всех потомков данного узла. Свойство используется только для чтения. Живой NodeList означает то, что если потомки узла изменяются, объект NodeList автоматически обновляется. NodeList — это объект типа массива, используемый для хранения упорядоченного списка узлов, доступных по позиции. NodeList не является экземпляром Array. Вы можете получить доступ к дочернему элементу текущего элемента через счетчик массива или метод item().
const elem = document.getElementById('list');
const count = elem.childNodes.length;
const firstChild = elem.childNodes.item(0);
console.log(count); // 9 
console.log(firstChild); // [object Text]
Когда DOM конструируется браузером, текстовые узлы создаются как из пробелов, так и из текстовых символов, поэтому в данном примере каждый символ разрыва строки считается как текстовый узел.
3.3.2. Свойство parentNode
Каждый узел имеет свойство parentNode, указывающее на его родителя в дереве документа. Свойство возвращает ссылку на внешний узел, который отражается как объект, принадлежащий документу. Все узлы, содержащиеся в списке дочерних узлов, имеют одного и того же родителя, поэтому каждое из их свойств родительского узла указывает на один и тот же узел. Если нет такого узла, по причине того, что узел находится вверху дерева или не относится к дереву, данное свойство вернет null. Свойство parentNode текстового фрагмента — это внешний узел или элемент, охватывающий этот фрагмент.
const elem = document.getElementById('list');
const parentElem = elem.parentNode;
document.write(parentElem); // [object HTMLBodyElement]
3.3.3. Свойства previousSibling и nextSibling
Можно переходить от одного узла в списке к другому, используя свойства previousSibling и nextSibling. Свойства используются только для чтения.
Свойство previousSibling возвращает узел, представляющий предыдущий одноуровневый узел в дереве или null, если не такого узла.
Свойство nextSibling возвращает узел, представляющий следующий одноуровневый узел в дереве или null, если не такого узла.
Первый узел в списке имеет значение null для его свойства previousSibling, а последний узел в списке имеет значение null для его свойства nextSibling.
const list = document.querySelector('ul');
console.log(list.nextSibling.nodeName); // #text
console.log(list.previousSibling.nodeName); // #text
3.3.4. Свойства firstChild и lastChild
Свойства firstChild и lastChild возвращают узел, представляющий первый или последний потомок узла в дереве или null, если узел не имеет потомков. Свойства используются только для чтения. Они полезны, когда вы хотите вставить новый дочерний элемент до или после всех остальных, и вам нужна точка отсчета для методов, которые добавляют элементы в список узлов документа.
<p id="p1"></p>
<p id="p2"> </p>
console.log(document.getElementById('p1').firstChild); // null
console.log(document.getElementById('p2').lastChild.nodeName); // #text
3.3.5. Свойство parentElement
Свойство parentElement возвращает элемент, который является родителем данного узла. Если узел не имеет родителя или если родитель не элемент, это свойство вернет null. Свойство работает только с элементами HTML, которые отражаются как объекты документа, тогда как узел не обязательно является элементом HTML (например, атрибутом или текстовым фрагментом). Используется только для чтения.
<ul id="list">
   <li>Пункт 1</li>
   <li>Пункт 2</li>
   <li><a href="https://google.com">Пункт 3</a></li>
   <li>Пункт 4</li>
</ul>
<p id="result"></p>
const parentEl = document.getElementById('list').parentElement;
document.getElementById('result').innerHTML = 'Объект: ' + parentEl + '
' + ' Имя узла:' + ' ' + parentEl.nodeName;

3.3.6. Свойство ownerDocument
Свойство ownerDocument возвращает документ, в контексте которого узел был создан. Если нет связанного с ним документа, возвращает null. Свойство ownerDocument объекта предоставляет способ создания ссылок на другие объекты в том же документе или для доступа к свойствам и методам объекты документа, обеспечивая быстрый доступ к узлу документа без необходимости обхода иерархии узлов до самого верха. Свойство полезно при определении, к какому документу принадлежит элемент <iframe>, новое окно, вкладка или XML-документ. Используется только для чтения.
<iframe src="https://player.vimeo.com/video/159120552?byline=0&portrait=0&badge=0" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
const frame = document.querySelector('iframe');
console.log(frame.ownerDocument.location.href);
3.4. Другие свойства узлов: baseURI, isConnected и textContent
Свойство baseURI
Свойство baseURI возвращает базовый URL-адрес документа. В HTML это соответствует протоколу, доменному имени и структуре каталогов, все до последнего /. Это свойство удобно в приложениях, которые импортируют данные XML, и в этом случае источник элемента XML, вероятно, отличается от страницы HTML, на которой он обрабатывается. Используется только для чтения.
<p id="result"></p>
const pageURI = document.baseURI;
document.getElementById('result').innerHTML = 'Базовый URL страницы: ' + pageURI;
Свойство isConnected
Свойство isConnected возвращает логическое значение, указывающее, подключен ли узел (напрямую или косвенно) к объекту контекста, например объекту Document в случае обычного DOM или ShadowRoot в случае теневого DOM. Используется только для чтения.
const test = document.createElement('p');
console.log(test.isConnected); // false
document.body.appendChild(test);
console.log(test.isConnected); // true
Свойство textContent
Свойство textContent можно использовать для получения всех дочерних текстовых узлов, а также для установки содержимого узла в определенный текстовый узел. Когда он используется для получения текстового содержимого узла, он возвращает объединенную строку всех текстовых узлов, содержащихся в узле. В отличие от innerText, возвращает любой встроенный стиль или код сценария вместе с другим текстом. Когда свойство textContent используется для установки текста, содержащегося в узле, оно удалит все дочерние узлы, заменив их на новое текстовое содержимое.
<p id="result"></p>
<p id="text">Текст</p>
document.getElementById('result').textContent = 'Какой-то текст';
const text = document.getElementById('text').textContent;
console.log(text); // Текст
4. Манипуляции узлами
4.1. Создание новых узлов
4.1.1. Метод appendChild()
Метод appendChild() добавляет узел (или несколько узлов) в конец списка дочерних узлов родительского узла, на котором вызывается метод. Если дочерних узлов нет, узел добавится в качестве первого дочернего узла.
<p>Привет</p>
const elementNode = document.createElement('b');
const textNode = document.createTextNode(' мир!');
//добавим эти узлы к DOM
document.querySelector('p').appendChild(elementNode);
document.querySelector('b').appendChild(textNode);

4.1.2. Метод cloneNode()
Метод cloneNode() позволяет дублировать один узел или узел и все его дочерние узлы. Принимает один логический аргумент, указывающий, следует ли выполнять глубокое копирование. Когда аргумент равен true, клонируется узел и все его поддерево; когда false, клонируется только начальный узел. Возвращаемый клонированный узел принадлежит документу, но ему не назначен родительский узел. Таким образом, клонированный узел не существует в документе до тех пор, пока не будет добавлен с помощью appendChild(), insertBefore() или replaceChild().
При клонировании узла элемента также клонируются все его атрибуты и их значения (включая встроенные события). Все, что добавлено с помощью addEventListener() или node.onclick, не клонируется.
<ul id="menu">
   <li>Главная</li>
   <li>Услуги</li>
   <li>О нас</li>
   <li>Контакты</li>
</ul>
const menu = document.querySelector('#menu').cloneNode(true);
menu.setAttribute('id', 'menu-mobile');    
document.body.appendChild(menu);

4.1.3. Метод insertBefore()
Метод insertBefore() вставляет узел перед другим узлом в качестве дочернего узла родительского узла. Принимает два параметра, указанные через запятую, — узел для вставки и узел, перед которым будет вставлен новый узел. Если у родительского узла нет дочерних узлов, то после вставки узел будет единственным дочерним узлом.
<ul id="menu">
   <li>Услуги</li>
   <li>О нас</li>
   <li>Контакты</li>
</ul>
const menu = document.getElementById('menu');
// создаем новый узел li 
const li = document.createElement('li');
li.textContent = 'Главная';
// вставляем новый узел перед первым элементом списка 
menu.insertBefore(li, menu.firstElementChild);
4.1.4. Метод replaceChild()
Метод replaceChild() заменяет один узел другим. Метод принимает два аргумента: узел для вставки и узел для замены. Когда узел вставляется с помощью replaceChild(), все его указатели отношений дублируются из узла, который он заменяет. Несмотря на то, что замененный узел технически по-прежнему принадлежит тому же документу, он больше не имеет определенного местоположения в документе.
<div id="div-1">Элемент 1</div>
<div id="div-2">Элемент 2</div>
//замена узла элемента
const divFirst = document.getElementById('div-1');
var newP = document.createElement('p');
newP.textContent = 'Новый элемент 1';
divFirst.parentNode.replaceChild(newP, divFirst);
//замена текстового узла
const divSecond = document.getElementById('div-2').firstChild;
const divText = document.createTextNode('Элемент 2 новый текст');
divSecond.parentNode.replaceChild(divText, divSecond);

4.1.5. Метод removeChild()
Метод removeChild() удаляет дочерний узел из родительского узла. Удаление происходит в несколько этапов: сначала нужно выбрать узел, который хотите удалить; затем получить доступ к его родительскому элементу, как правило, с помощью свойства parentNode. После чего вызвать метод removeChild(), передавая ему ссылку на удаляемый узел.
Удалённый дочерний узел остаётся в памяти, но больше не является частью DOM. Повторно использовать удалённый узел можно с помощью ссылки на объект — oldChild.
//удаление узла элемента без указания его родительского узла
const divFirst = document.getElementById('div-1');     
divFirst.parentNode.removeChild(divFirst);
//удаление текстового узла
const divSecond = document.getElementById('div-2').firstChild;      
divSecond.parentNode.removeChild(divSecond);
4.2. Проверка позиции узла в дереве DOM: методы compareDocumentPosition() и contains()
Метод compareDocumentPosition()
Метод compareDocumentPosition() определяет связь между двумя узлами и возвращает битовую маску, указывающую на связь. Значения битовой маски показаны в следующей таблице. Узел может иметь более одного типа отношений с другим узлом. Например, когда узел одновременно содержит (16) и предшествует (4), возвращаемое значение из compareDocumentPosition() будет равно 20.
| Числовой код | Описание | 
|---|---|
| 1 | DOCUMENT_POSITION_DISCONNECTED Означает, что два узла не принадлежат одному и тому же документу.  | 
| 2 | DOCUMENT_POSITION_PRECEDING Означает, что переданный узел предшествует выбранному узлу.  | 
| 4 | DOCUMENT_POSITION_FOLLOWING Означает, что переданный узел следует за выбранным узлом.  | 
| 8 | DOCUMENT_POSITION_CONTAINS Означает, что переданный узел является предком выбранного узла.  | 
| 16 | DOCUMENT_POSITION_CONTAINED_BY Означает, что переданный узел является потомком выбранного узла.  | 
| 32 | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC Означает, что два узла не имеют отношения друг к другу или являются двумя атрибутами одного и того же элемента.  | 
<p id="p1">Первый параграф</p>
<p id="p2">Второй параграф</p>
const p2Position = p1.compareDocumentPosition(p2); // p1 - узел, который сравнивается, p2 - узел, с которым идёт сравнение
console.log(p2Position); // 4, то есть p2 идет за p1
Метод contains()
Метод contains() позволяет узнать, является ли данный узел потомком другого. Метод вызывается для узла-предка, с которого должен начинаться поиск, и принимает единственный аргумент, который является предполагаемым узлом-потомком. Метод возвращает значение true, если узел является потомком данного узла, в противном случае возвращает false.
<body>
   <header></header>
   <main></main>
   <footer></footer>
   <script></script>
 </body>
const footerNode = document.querySelector('footer');
const scriptNode = document.querySelector('script');
console.log(footerNode.contains(scriptNode)); // false
Метод также можно использовать, например, для проверки, содержит ли данный элемент указанный класс:
<body class="post-template-default single single-post single-format-standard"></body>
const bodyClass = document.body;
console.log(bodyClass.classList.contains('post-template-default')); // true
4.3. Определение идентичности узлов с помощью метода isEqualNode()
Метод isEqualNode() проверяет равенство двух узлов. Два узла равны, если выполняются следующие условия:
- Узлы одного типа;
 - Атрибуты nodeName, localName, namespaceURI, prefix и nodeValue нулевые или имеют одинаковую длину и идентичны посимвольно;
 - Атрибуты NamedNodeMaps равны нулю или имеют одинаковую длину, и для каждого узла, существующего в одной карте, есть узел, который существует в другой карте и является равным, хотя и не обязательно с тем же индексом.
 - Списки узлов дочерних узлов равны, то есть они оба нулевые или имеют одинаковую длину и содержат одинаковые узлы с одним и тем же индексом. Рекомендуется нормализовать узлы перед сравнением.
 
<ul>
   <li><a href="">Ссылка</a></li>
   <li><a href="">Ссылка</a></li>
</ul>
<p>Параграф 1</p>
<p>Параграф 2</p>
const listItem = document.querySelectorAll('li');
console.log(listItem[0].isEqualNode(listItem[1])); // true
const p = document.querySelectorAll('p');
console.log(p[0].isEqualNode(p[1])); // false
4.4. Определение отношений между узлами: методы hasChildNodes() и getRootNode()
Метод hasChildNodes()
Метод hasChildNodes() возвращает true, если узел имеет один или несколько дочерних узлов, и false в противном случае. Этот способ более эффективный, чем запрос childNodes.length.
<ul id="list">
   <li>Пункт 1</li>
   <li>Пункт 2</li>
   <li><a href="https://google.com">Пункт 3</a></li>
   <li>Пункт 4</li>
</ul>
const listItems = document.getElementById("list");
if ( listItems.hasChildNodes() ) {
  listItems.removeChild( listItems.firstElementChild );
}
Метод getRootNode()
Метод getRootNode() возвращает корневой узел. Вызов для элемента внутри стандартной веб-страницы вернет объект HTMLDocument, представляющий всю страницу.
Вызов для элемента внутри теневого DOM вернет связанный с ним ShadowRoot. 
<div class="js-parent">
   <div class="js-child"></div>
</div>
<div class="js-shadowHost"></div>
const parent = document.querySelector('.js-parent'),
   child = document.querySelector('.js-child'),
   shadowHost = document.querySelector('.js-shadowHost');
console.log(parent.getRootNode().nodeName); // #document
console.log(child.getRootNode().nodeName); // #document
// создадим теневое дерево
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = 'Содержимое теневого дерева';
const shadowChild = shadowRoot.querySelector('.js-shadowChild');
console.log(shadowChild.getRootNode() === shadowRoot); // true
console.log(shadowChild.getRootNode({ composed: false }) === shadowRoot); // true
console.log(shadowChild.getRootNode({ composed: true }).nodeName); // #document
5. Пространства имен XML: методы lookupNamespaceURI(), isDefaultNamespace() и lookupPrefix()
Пространства имен XML позволяют размещать в одном документе элементы из разных языков, основанных на XML, не опасаясь конфликтов имен элементов. Пространства имен объявляются с использованием семейства зарезервированных атрибутов. Имя такого атрибута должно быть либо xmlns, либо иметь xmlns: в качестве префикса.
Описанные ниже методы в первую очередь полезны, когда у вас есть ссылка на узел, но вы не знаете его связи с остальной частью документа.
<svg xmlns:svg="http://www.w3.org/2000/svg" height="1"></svg>
Метод lookupNamespaceURI()
Метод lookupNamespaceURI() принимает префикс в качестве параметра и возвращает пространство имен, представленное префиксом (prefix), или пространство имен по умолчанию, если аргумент prefix является пустой строкой.
Когда метод вызывается с префиксом в качестве аргумента, он должен возвращать URI пространства имен для данного префикса. Когда метод lookupNamespaceURI() вызывается с пустой строкой в качестве аргумента (представляющего пространство имен по умолчанию), он должен выполнить одно из следующих действий:
Если существует пространство имен по умолчанию, возвращает URI пространства имен по умолчанию. Если пространства имен по умолчанию нет, возвращает либо пустую строку, либо null, либо, если это разрешено привязкой языка, — undefined.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.lookupNamespaceURI("")); // http://www.w3.org/2000/svg
Метод isDefaultNamespace()
Метод isDefaultNamespace() принимает URI пространства имен в качестве аргумента. Он возвращает логическое значение, которое равно true, если пространство имен является пространством имен по умолчанию на данном узле, и false в противном случае. Пространство имен HTML-элемента по умолчанию всегда равно "". Для элемента SVG он задается атрибутом xmlns.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.isDefaultNamespace("")); // false
console.log(svgElem.isDefaultNamespace("http://www.w3.org/2000/svg")); // true
Метод lookupPrefix()
Метод lookupPrefix() возвращает строку, содержащую префикс для данного URI пространства имен, если он присутствует, и null в противном случае. Если с префиксом пространства имен связано более одного префикса, возвращаемый префикс пространства имен зависит от реализации.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.lookupPrefix("http://www.w3.org/2000/svg")); // null
6. Объединение родственных текстовых узлов в один с помощью метода normalize()
Метод normalize() используется для объединения родственных текстовых узлов в один текстовый узел. Родственные текстовые узлы обычно встречаются тогда, когда текст программно добавляется в DOM.
<div></div>
const pElem = document.createElement('p');
const text1 = document.createTextNode('Привет');
const text2 = document.createTextNode(' мир!');
pElem.appendChild(text1);
pElem.appendChild(text2);
document.querySelector('div').appendChild(pElem);
console.log(document.querySelector('p').childNodes.length); // 2
document.querySelector('div').normalize(); 
console.log(document.querySelector('p').childNodes.length); // 1
По материалам DOM Level 3, DOM Level 4, Node