DOM-дерево в JavaScript: как устроена объектная модель документа

Браузер не работает с вашим HTML напрямую: он превращает разметку в дерево объектов, и дальше всё, что вы видите на экране, живёт в нём. Разобрали DOM-дерево для тех, кто знает вёрстку и делает первые шаги в JavaScript: из каких узлов состоит документ, как искать и менять элементы, ловить клики и не сажать скорость страницы. Внутри три таблицы-шпаргалки, семь типовых ошибок новичка и практика в консоли браузера, для которой не нужно ничего устанавливать.
Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 2323 статьи автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 2984 экспертных мнения Подписаться на Телеграм-канал
Обложка: DOM дерево в JavaScript: как устроена объектная модель документа

Вы написали разметку, открыли страницу в браузере, дописали пару строк на JavaScript, и в консоли появляется null. Браузер как будто читает какой-то другой файл. Он читает именно ваш, просто хранит результат чтения в своём формате: в виде дерева объектов. Это дерево и называется DOM.

CheckroiCheckroiПодборка курсов по DOM26 курсов • 10 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить

Ниже разобрали дерево документа по слоям: как браузер его собирает, из каких узлов оно состоит, как по нему ходить, как искать элементы, менять текст и разметку, ловить клики и не сажать при этом скорость страницы. С таблицами, примерами кода и разбором семи ошибок, на которых спотыкаются почти все новички.

Если разметка пока в новинку, стоит начать с материала «Что такое язык разметки HTML»: там про теги, вложенность и структуру документа, без которых дальше будет тяжело.

Статья написана для тех, кто знает HTML и делает первые шаги в JavaScript. Если вы ещё выбираете, браться ли за язык вообще, у нас есть отдельный разбор: зачем новичку учить JavaScript и что он даёт на практике.

А если хочется системного пути, а не обрывочных статей, загляните в подборку курсов по JavaScript: там 198 программ от коротких интенсивов по вёрстке до годовых курсов фронтенда.

CheckroiCheckroiПодборка курсов по javaScript179 курсов • 30 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить

Что такое DOM и почему браузер видит страницу иначе, чем вы её написали

Рой-фронтендер разбирает страницу сайта на составные блоки

DOM расшифровывается как Document Object Model, по-русски это объектная модель документа. Когда браузер получает от сервера HTML-файл, он не показывает его как есть. Сначала он разбирает текст разметки и строит из него структуру в памяти: каждый тег превращается в объект со своими свойствами, а вложенность тегов превращается во вложенность объектов.

Это DOM дерево браузер держит в памяти всё время, пока открыта вкладка. Дальше вся работа идёт уже с ним. Стили применяются к нему, JavaScript обращается к нему, картинка на экране рисуется по нему. Исходный HTML после разбора никого больше не интересует: он сделал свою работу и остался в истории загрузки.

Отсюда следует вещь, которая многих сбивает с толку в первый месяц. Разметка в файле и дерево документа в браузере расходятся почти сразу. Скрипт добавил блок с уведомлением, пользователь открыл выпадающее меню, библиотека подставила рекламный баннер. В файле ничего этого нет, а в дереве есть. Именно поэтому вкладка Elements в инструментах разработчика показывает совсем не тот текст, который лежит у вас в редакторе.

Простая аналогия. HTML-файл похож на рецепт, а объектная модель документа похожа на готовое блюдо на столе. Рецепт после готовки остаётся прежним, блюдо можно посолить, разложить по тарелкам и половину съесть.

Само дерево браузер отдаёт JavaScript через набор свойств и методов, который называется DOM API. Через него скрипт получает доступ к любому элементу страницы: читает текст, меняет классы, создаёт новые блоки, удаляет старые. Без этого моста язык умел бы считать числа и складывать строки, но не мог бы изменить на экране ни одной буквы.

Как браузер строит DOM-дерево из разметки

Сборка идёт сверху вниз, по мере чтения файла. Браузер встречает открывающий тег, создаёт для него узел, вешает узел на текущего родителя и спускается внутрь. Встречает закрывающий тег, поднимается обратно. Так из плоского текста получается иерархия.

Возьмём небольшую страницу:

<html>
  <head>
    <title>Мой сайт</title>
  </head>
  <body>
    <h1 class="title">Привет</h1>
    <ul id="menu">
      <li>Главная</li>
      <li>Контакты</li>
    </ul>
  </body>
</html>

Схема DOM дерева для этой страницы выглядит так:

document
└─ html
   ├─ head
   │  └─ title
   │     └─ "Мой сайт"        ← текстовый узел
   └─ body
      ├─ h1.title
      │  └─ "Привет"          ← текстовый узел
      └─ ul#menu
         ├─ li → "Главная"
         └─ li → "Контакты"

На вершине сидит объект document, корень всего дерева и точка входа для скрипта. Именно от него вы отталкиваетесь, когда пишете document.querySelector(...). Ниже идёт единственный элемент html, у него двое детей, и дальше по цепочке до самых листьев.

Листьями почти всегда оказываются текстовые узлы: строка «Главная» внутри li живёт отдельным узлом, у которого своих детей уже нет.

Ещё одна деталь, важная на практике: браузер терпелив к кривой разметке. Забыли закрыть <div>, вложили <p> в <p>, поставили <li> без списка: он всё равно построит дерево, просто по своим правилам восстановления. Итог может сильно отличаться от задуманного, и потом полдня уходит на вопрос «почему стиль применился к соседнему блоку». Проверять результат стоит во вкладке Elements, а не в редакторе кода.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Из каких узлов состоит дерево документа

Схема дерева документа из светящихся узлов, Рой рассматривает её снизу

Узел (по-английски node) — общее название для всего, что висит в дереве. Элементы, текст, комментарии, сам документ: всё это разные типы узлов DOM-дерева. Различать их важно: половина странного поведения кода объясняется тем, что вы схватили узел не того типа.

Тип узла Что это Пример Как часто встречается в коде
Document Корень дерева, вся страница целиком document Постоянно: с него начинается любой поиск
Element Обычный тег разметки <div>, <ul>, <img> Основной рабочий тип, 90 % времени
Text Текст внутри тега, включая пробелы и переносы строк «Привет» внутри <h1> Часто мешает при переборе детей
Comment Комментарий в разметке <!-- меню --> Почти никогда, но в дереве лежит
Attr Атрибут элемента class="title" Редко напрямую: обычно через getAttribute
DocumentFragment Лёгкий контейнер для сборки узлов вне страницы Служебный Пригодится в разделе про скорость

Почему текстовые узлы портят жизнь

Переносы строк и отступы в разметке тоже становятся текстовыми узлами. Возьмите красиво отформатированный список из примера выше и спросите у браузера количество детей:

const menu = document.getElementById('menu')

console.log(menu.childNodes.length)  // 5
console.log(menu.children.length)    // 2

Пять против двух. Разница в трёх текстовых узлах: перенос строки перед первым li, между двумя li и после второго. Свойство childNodes отдаёт вообще все узлы, а children отдаёт только элементы. Для повседневных задач нужен второй вариант, и это правило стоит запомнить сразу.

Как ходить по дереву: родители, дети и соседи

Родственные связи в дереве описываются теми же словами, что и в семье. У узла есть родитель, дети, братья и сёстры (соседи по уровню), предки и потомки. У каждой связи своё свойство.

Свойство или метод Что возвращает Учитывает текстовые узлы
parentElement Ближайший родитель-элемент Нет
children Коллекцию дочерних элементов Нет
childNodes Коллекцию всех дочерних узлов Да
firstElementChild, lastElementChild Первого и последнего ребёнка-элемент Нет
nextElementSibling, previousElementSibling Соседа справа и слева Нет
closest('селектор') Ближайшего предка, подходящего под селектор Нет
contains(узел) true, если узел лежит внутри Да

На практике чаще всего нужен closest. Допустим, вы делаете список товаров, и в каждой карточке есть кнопка «В корзину». По клику вам нужна карточка целиком: из неё надо прочитать цену и название.

button.addEventListener('click', (event) => {
  const card = event.target.closest('.product')
  console.log(card.dataset.price)
})

Метод поднимается вверх по цепочке предков, пока не встретит подходящий элемент, и избавляет от конструкций вида parentElement.parentElement.parentElement, которые ломаются от любой правки вёрстки.

Как найти нужный элемент на странице

С поиска начинается любая работа с DOM в JavaScript. Методов несколько, и разница между ними влияет и на скорость, и на то, что именно вам вернётся.

Метод Что принимает Что возвращает Когда брать
getElementById('id') Только идентификатор, без решётки Один элемент или null Когда у элемента есть уникальный id
querySelector('селектор') Любой CSS-селектор Первый подходящий элемент или null Универсальный вариант на каждый день
querySelectorAll('селектор') Любой CSS-селектор Статичный список NodeList Когда нужны все совпадения сразу
getElementsByClassName('class') Имя класса Живую коллекцию HTMLCollection Редко: список меняется под руками
getElementsByTagName('tag') Имя тега Живую коллекцию HTMLCollection Редко, для массовых обходов

Если сомневаетесь, что выбрать, берите querySelector и querySelectorAll. Синтаксис у них совпадает с CSS, который вы уже знаете по вёрстке, и одним методом закрываются все случаи: '#menu', '.card .price', 'input[type="email"]', 'li:last-child'. Отдельный getElementById имеет смысл там, где важна скорость в цикле: по уникальному идентификатору браузер находит узел быстрее, чем разбирает селектор.

Живая коллекция и статичный список

Два семейства методов возвращают разные вещи, и это второй по частоте источник недоумения после текстовых узлов.

querySelectorAll отдаёт NodeList, слепок на момент вызова. Добавили после этого на страницу новый подходящий элемент, в слепке его не будет. getElementsByClassName отдаёт HTMLCollection, которая обновляется сама: элемент появился в документе, и он тут же оказался в коллекции. Звучит удобно, а на деле даёт классическую ловушку с бесконечным циклом, когда внутри перебора вы добавляете элементы с тем же классом.

Обе коллекции похожи на массив, но массивом не являются. У NodeList есть forEach, а вот map и filter нет. Если нужны методы массива, коллекцию сначала разворачивают:

const cards = [...document.querySelectorAll('.card')]

const expensive = cards.filter((card) => Number(card.dataset.price) > 5000)
console.log(expensive.length)

Как менять содержимое и структуру страницы

Дошли до самого приятного: правки, которые видно на экране сразу. Начнём с текста.

const title = document.querySelector('.title')

title.textContent = 'Привет ещё раз'

Свойство textContent кладёт в элемент простой текст. Если в строке встретятся угловые скобки, они останутся скобками и никакой разметкой не станут. Соседнее свойство innerHTML ведёт себя иначе: содержимое строки разбирается как разметка, теги внутри превращаются в настоящие элементы дерева.

Важный нюанс безопасности. Никогда не подставляйте в innerHTML то, что ввёл пользователь. Через это поле на страницу попадает чужой скрипт и получает доступ ко всему, до чего дотягивается ваш JavaScript, включая формы и cookie. Это классическая уязвимость под названием XSS. Для пользовательских данных существует textContent.

Создание новых элементов состоит из трёх шагов: создать, наполнить, вставить.

const item = document.createElement('li')   // создали узел
item.textContent = 'Доставка'               // наполнили
item.classList.add('menu__item')            // повесили класс

document.getElementById('menu').append(item) // вставили в дерево

Пока элемент не вставлен, на экране его нет: он существует только в памяти. Вставку делают методами append (в конец родителя), prepend (в начало), before и after (рядом с элементом). Удаление делается одной строкой: item.remove().

Работать с этим набором приходится в любой практической задаче: форма подписки, которая после отправки показывает благодарность, корзина с пересчётом суммы, фильтр каталога, галерея с подгрузкой. Всё это сводится к поиску нужного узла, правке текста и вставке новых элементов в нужное место дерева.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Атрибуты, классы и data-атрибуты

Классы удобнее всего менять через classList. У этого свойства четыре метода, и они закрывают почти всё:

const modal = document.querySelector('.modal')

modal.classList.add('is-open')       // добавить
modal.classList.remove('is-open')    // убрать
modal.classList.toggle('is-open')    // переключить
modal.classList.contains('is-open')  // проверить, вернёт true или false

Внешним видом правильнее управлять через переключение классов, а стили держать в CSS. Прямая запись в element.style работает, но разбрасывает оформление по скриптам, и через месяц никто не найдёт, откуда взялся розовый фон.

Обычные атрибуты читаются и пишутся через три метода: getAttribute('href'), setAttribute('href', '/contacts/') и removeAttribute('disabled'). А для своих данных в разметке есть отдельный механизм: атрибуты с приставкой data-:

<button data-product-id="482" data-price="5900">В корзину</button>
const button = document.querySelector('button')

console.log(button.dataset.productId) // '482'
console.log(button.dataset.price)     // '5900'

Обратите внимание на превращение data-product-id в productId: дефисы уходят, следующая буква становится заглавной. И ещё одно: в dataset всё лежит строками, поэтому перед арифметикой значение приводят к числу через Number().

События: как страница отвечает на действия пользователя

Клик, ввод в поле, отправка формы, прокрутка: всё это события. Скрипт подписывается на нужное событие у нужного элемента и получает управление, когда оно случается:

const form = document.querySelector('.subscribe')

form.addEventListener('submit', (event) => {
  event.preventDefault()   // отменяем перезагрузку страницы
  const email = form.querySelector('input[type="email"]').value
  form.textContent = `Спасибо, письмо ушло на ${email}`
})

В обработчик приходит объект события. Из него чаще всего берут два свойства: event.target (элемент, на котором событие случилось) и event.currentTarget (элемент, на котором висит обработчик). Метод preventDefault() отменяет поведение браузера по умолчанию: перезагрузку страницы при отправке формы, переход по ссылке.

Делегирование: один обработчик вместо сотни

События всплывают вверх по дереву. Клик по кнопке внутри карточки сначала срабатывает на кнопке, потом на карточке, потом на списке, потом на body. Это свойство используют, чтобы не вешать обработчик на каждый элемент по отдельности:

document.querySelector('.catalog').addEventListener('click', (event) => {
  const button = event.target.closest('.buy')
  if (!button) return

  addToCart(button.dataset.productId)
})

Один обработчик на весь каталог отлавливает клики по всем кнопкам, включая те, которых на странице ещё не было в момент загрузки. Для динамических списков делегирование остаётся единственным рабочим подходом: обычная подписка на элемент, который появится через минуту, просто не найдёт этот элемент.

Почему работа с DOM тормозит страницу

Каждое обращение к дереву стоит времени, а некоторые правки заставляют браузер пересчитывать положение элементов на экране. Пересчёт геометрии называется reflow, перерисовка без изменения размеров называется repaint. Первое дороже второго в разы.

Типичный пример неудачного кода, когда тысяча строк вставляется по одной:

// плохо: тысяча вставок и тысяча пересчётов
for (const name of names) {
  const li = document.createElement('li')
  li.textContent = name
  list.append(li)
}

Тот же результат за одну вставку через DocumentFragment (лёгкий контейнер, который живёт в памяти и не является частью страницы):

// хорошо: собрали в памяти, вставили один раз
const fragment = document.createDocumentFragment()

for (const name of names) {
  const li = document.createElement('li')
  li.textContent = name
  fragment.append(li)
}

list.append(fragment)

Ещё три привычки, которые экономят время браузера. Сохраняйте найденные элементы в переменные, вместо того чтобы искать их заново в каждой строке цикла. Меняйте классы вместо десятка правок style подряд. И не читайте геометрию (offsetHeight, getBoundingClientRect()) вперемешку с записью стилей: такое чередование заставляет браузер пересчитывать раскладку на каждом шаге.

Виртуальный DOM и Shadow DOM: где вы их встретите

Два похожих названия, за которыми стоят разные вещи, и каждое отличается от обычного дерева документа. Разберём коротко, потому что оба слова попадаются на первом же собеседовании.

Виртуальный DOM — приём из React и подобных библиотек. Библиотека держит в памяти обычный объект JavaScript, описывающий, как должна выглядеть страница. При изменении данных она собирает новое описание, сравнивает со старым и переносит в настоящее дерево только отличия. Смысл в том, чтобы делать меньше дорогих обращений к странице и не заставлять разработчика вручную следить за каждой правкой.

Shadow DOM — возможность самого браузера. Она позволяет спрятать внутреннее устройство компонента в отдельное поддерево, куда не достают внешние стили и селекторы. На этом механизме работают встроенные элементы вроде <video> с его кнопками и ползунком, а также пользовательские веб-компоненты.

Нужен ли DOM, когда есть React. Да, и первым делом. Библиотека избавляет от ручных вставок узлов, но её собственные события, ссылки на элементы и работа с формами построены поверх той же модели. Разработчик, который не понимает дерево документа, отлаживает чужую абстракцию вслепую.

Семь ошибок новичка при работе с DOM

Рой с чек-листом уверенно обходит расставленные ловушки

Ошибка 1: скрипт запускается раньше разметки

Самая частая причина null в консоли. Скрипт подключён в <head> и выполняется, когда нужного элемента в дереве ещё нет. Лечится атрибутом defer у тега <script>, подключением скрипта перед закрывающим </body> или подпиской на событие DOMContentLoaded, которое срабатывает после сборки дерева.

Ошибка 2: решётка и точка там, где их не ждут

В getElementById идентификатор передают без решётки: getElementById('menu'). В querySelector наоборот, полным селектором: querySelector('#menu'). Перепутанный синтаксис возвращает null без единого сообщения об ошибке.

Ошибка 3: коллекцию принимают за элемент

document.querySelectorAll('.card').style.color = 'red' не сработает никогда. Метод вернул список, а свойство style есть у отдельного элемента. Нужен перебор через forEach либо обращение по индексу.

Ошибка 4: пользовательский текст уходит в innerHTML

Имя из формы, комментарий, поисковый запрос: всё это подставляют через textContent. Через innerHTML на страницу попадает чужой код, и уязвимость XSS открывается за одну строку.

Ошибка 5: обработчики вешают в цикле по каждому элементу

Для десяти кнопок разница незаметна, для тысячи строк таблицы уже ощутима. Плюс новые элементы, добавленные позже, останутся без обработчика. Решение описано выше: делегирование через общего родителя.

Ошибка 6: поиск повторяется внутри цикла

Строка document.querySelector('.total') внутри перебора из пятисот элементов выполняет пятьсот одинаковых обходов дерева. Результат поиска сохраняют в переменную до цикла.

Ошибка 7: правки вносят по одной

Десять подряд идущих изменений style и десять вставок узлов заставляют браузер пересчитывать раскладку снова и снова. Собирайте изменения через фрагмент и переключайте классы вместо точечных правок оформления.

Как потренироваться прямо сейчас в консоли браузера

Для первых экспериментов не нужны ни редактор, ни установка чего-либо. Откройте любой сайт, нажмите F12 (на macOS это Cmd+Option+I) и перейдите на вкладку Console. Всё, что вы там напишете, выполнится на живой странице.

Попробуйте по шагам:

  1. document.title: посмотреть заголовок вкладки, а потом присвоить ему свою строку и увидеть, как меняется название вкладки.
  2. document.querySelectorAll('a').length: посчитать все ссылки на странице.
  3. document.querySelector('h1').textContent = 'Моя версия': переписать главный заголовок.
  4. document.body.style.background = 'papayawhip': перекрасить фон.
  5. Обновить страницу и убедиться, что всё вернулось на место.

Последний пункт снимает главный страх новичка: сломать чужой сайт из консоли невозможно. Вы правите копию дерева у себя в браузере, на сервере ничего не меняется, и перезагрузка страницы стирает все эксперименты.

Рядом с консолью живёт вкладка Elements: это те же инструменты разработчика, которые чаще называют DevTools. Там дерево документа показано в том виде, в каком оно существует прямо сейчас, со всеми правками скриптов. Клик по узлу подсвечивает элемент на странице, правая кнопка даёт возможность изменить разметку, а панель справа показывает применённые стили. Это самое быстрое место, чтобы понять, почему получилось не то, что вы задумали.

CheckroiCheckroiПодборка курсов по DevTools9 курсов • 7 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить

Где научиться работать с DOM

Дерево документа само по себе изучается за неделю, а уверенное владение приходит вместе с языком: событиями, асинхронностью, работой с сервером и форматом JSON, в котором приходят данные. Проще пройти обучение по готовой программе, где темы идут в правильном порядке и есть практика с проверкой, чем собирать знания из разрозненных статей.

Отдельные программы разбирают работу с деревом документа подробно: у нас собрана подборка курсов с блоком по DOM: 27 программ, где тема разбирается с практикой, а не одним слайдом.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
JavaScript
Перейти на сайт курса
SkillboxSkillbox63 829 ₽4086 ₽/мес.3 месяцаОбзор курса
Факультет fullstack JavaScript
Перейти на сайт курса
GeekBrainsGeekBrains134 700 ₽3742 ₽/мес.15 месяцевОбзор курса
Node.js-разработчик
Перейти на сайт курса
Академия ЭдюсонЭдюсон95 000 ₽3958 ₽/мес.8 месяцевОбзор курса
Fullstack-разработчик на JavaScript
Перейти на сайт курса
Академия ЭдюсонЭдюсон158 760 ₽6615 ₽/мес.11 месяцевОбзор курса
Фулстек-разработчик на JavaScript
Перейти на сайт курса
SkillboxSkillbox153 348 ₽4296 ₽/мес.11 месяцевОбзор курса
Backend-разработка на Node.js
Перейти на сайт курса
НетологияНетология45 000 ₽2500 ₽/мес.6 месяцевОбзор курса
Fullstack-разработчик на Node.js
Перейти на сайт курса
HexletHexlet125 100 ₽7141 ₽/мес.12 месяцевОбзор курса
Fullstack разработчик JavaScript
Перейти на сайт курса
OTUSOTUS75 000 ₽20 000 ₽/мес.6 месяцевОбзор курса
Автоматизированное тестирование веб-приложений на JavaScript
Перейти на сайт курса
SkillboxSkillbox42 900 ₽3575 ₽/мес.4 месяцаОбзор курса
Node.js-разработчик
Перейти на сайт курса
HexletHexlet74 970 ₽4280 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по JavaScript

Если смотреть шире, работа с деревом документа входит в профессию фронтендера. Что входит в эту роль дальше и сколько за неё платят, разобрали в материалах «Как стать фронтенд-разработчиком» и «Кто такой JavaScript-разработчик». А тем, кто пока выбирает язык и путается в названиях, пригодится разбор разницы между Java и JavaScript.

Часто задаваемые вопросы

Что такое DOM простыми словами?

DOM (Document Object Model, объектная модель документа) — это структура в памяти браузера, в которую превращается ваш HTML после загрузки. Каждый тег становится объектом, вложенность тегов становится вложенностью объектов, и получается дерево. Именно с этим деревом работают стили, скрипты и сам браузер, когда рисует страницу.

Чем DOM отличается от HTML-кода?

HTML — это текст файла, который вы написали, а дерево документа — результат его разбора браузером. Расходиться они начинают сразу: скрипты добавляют блоки, пользователь открывает меню, библиотеки подставляют свои элементы. Поэтому вкладка Elements в инструментах разработчика показывает текущее состояние дерева, а не содержимое вашего файла.

Из каких узлов состоит DOM-дерево?

Основных типов пять: Document (корень), Element (теги), Text (текст внутри тегов, включая пробелы и переносы строк), Comment (комментарии) и Attr (атрибуты). В повседневной работе вы имеете дело с элементами, а текстовые узлы чаще всего мешают: из-за них childNodes возвращает больше детей, чем ожидаешь.

Что выбрать: getElementById или querySelector?

Если у элемента есть уникальный идентификатор и код выполняется в цикле, быстрее сработает getElementById. Во всех остальных случаях удобнее querySelector: он принимает любой CSS-селектор, который вы уже знаете по вёрстке, и одним методом закрывает поиск по классу, тегу, атрибуту и вложенности.

Почему getElementById возвращает null?

Чаще всего скрипт выполняется раньше, чем браузер собрал нужную часть дерева. Помогает атрибут defer у тега script, подключение скрипта перед закрывающим тегом body или подписка на событие DOMContentLoaded. Вторая частая причина — синтаксис: в getElementById идентификатор передают без решётки, а в querySelector с решёткой.

Когда использовать innerHTML, а когда textContent?

Для любого текста, который пришёл от пользователя или из внешнего источника, нужен textContent: он подставляет строку как обычный текст. innerHTML разбирает строку как разметку, поэтому через него на страницу попадает чужой скрипт — это уязвимость XSS. Свой собственный HTML через innerHTML вставлять можно, чужие данные никогда.

Нужно ли учить DOM, если я собираюсь писать на React?

Да, и в первую очередь. React избавляет от ручных вставок узлов, но его события, ссылки на элементы и работа с формами построены поверх той же модели документа. Разработчик, который не понимает дерево, отлаживает ошибки библиотеки вслепую и не может объяснить, почему обработчик не сработал.

Где потренироваться работать с DOM без установки программ?

В консоли браузера. Откройте любой сайт, нажмите F12, перейдите на вкладку Console и попробуйте document.querySelectorAll('a').length или document.querySelector('h1').textContent = 'Моя версия'. Правки видны сразу, при этом вы меняете только копию дерева у себя в браузере: перезагрузка страницы всё вернёт на место.

Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!