Что умеет браузер: window, DOM и BOM

окружение≈ 7 минут

Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.

Язык вы уже знаете — теперь у него появляется среда обитания. Вокруг вашего кода в браузере лежит целый мир: объект window, дерево страницы и десятки готовых интерфейсов, которых в самом языке нет и никогда не было.

Разделы темы:·

У вашего кода в браузере есть хозяин — объект window. Он одновременно и окно вкладки, и глобальный объект: всё, что объявлено глобально, и всё, что даёт браузер, становится его свойством. Поэтому document и window.document — одно и то же имя, просто префикс обычно не пишут.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Из этого следует неприятное: глобальная область в браузере — не пустая комната, а чужая квартира с мебелью. Ваше глобальное имя может совпасть с уже существующим свойством окна, и тогда победит не ваш код.

У window заранее заняты совсем обычные имена: name, length, top, status, closed. Присвойте глобально name = 42 — и прочитаете обратно строку «42»: за этим именем стоит браузерный сеттер, который приводит значение к строке. Ещё один довод не заводить глобальные переменные вообще.

Получив HTML, браузер не хранит его как текст. Он разбирает разметку и строит дерево объектов — DOM, Document Object Model. Корень дерева лежит в document, ниже идут элементы, текстовые узлы и комментарии; у каждого узла свои свойства и методы.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Дерево живое. Меняете свойство объекта — страница перерисовывается, добавляете узел — он появляется на экране. Обратной связи с исходным HTML нет: исходник давно прочитан и забыт, вы работаете с деревом.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Строку можно отдать браузеру, но обратно вы получите узлы, а не текст: парсер отрабатывает сразу же.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

DOM отвечает за содержимое страницы. Всё, что вокруг неё — адрес, история переходов, сведения о браузере и экране — собрано под неофициальным именем BOM, Browser Object Model. Спецификации ровно с таким названием не существует; это просто удобная граница между «страницей» и «окном».

Главные жильцы: location — адрес, разобранный на части; history — кнопки «назад» и «вперёд»; navigator — паспорт браузера и точка входа во многие возможности устройства; screen — размеры экрана. Устроен location так же, как обычный URL, поэтому его удобно изучать на любом адресе.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Сам язык даёт синтаксис и скромный набор встроенных объектов: Object, Array, Math, JSON, Promise. Всё остальное, чем вы пользуетесь в браузере — DOM, события, таймеры, fetch, хранилища, звук, камера — это Web API: интерфейсы, которые хост подкладывает в тот же глобальный объект.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Типичный Web API — объект с методами и событиями. И событие не обязано приходить от человека: вызов element.click() или dispatchEvent запускает ровно ту же цепочку обработчиков, что и настоящее нажатие. На этом держатся и отладка, и тесты.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Один и тот же движок исполняет JavaScript и в Chrome, и в Node.js — но окружения у них разные. В Node нет ни window, ни document: там нечего рисовать. Зато есть файловая система, процессы и сеть без ограничений браузера.

ЧтоБраузерNode.js
Глобальный объектwindowglobal
Общее имя для обоихglobalThisglobalThis
Страницаdocument, элементы, событияDOM отсутствует
Файлытолько то, что дал пользовательмодуль node:fs, весь диск
Сетьfetch с правилами CORSлюбые сокеты, CORS не действует
Где выполняется кодна чужом устройствена вашем сервере

Отсюда практическое правило: библиотека, которая трогает document, не заведётся на сервере, а та, что читает файлы через node:fs, не соберётся для браузера. Универсальный код пишут через globalThis и проверку возможностей.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Ни один учебник не перечислит все Web API — их сотни, и список растёт. Зато окружение отвечает на вопросы само: наберите в консоли DevTools document. и получите список свойств, а console.dir(document.body) покажет элемент как объект, а не как разметку.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Такая проверка называется feature detection: если API нет, включают запасной путь, а не падают. Консоль, правда, знает только про ваш браузер — на вопрос «а есть ли это в Safari» отвечают MDN и caniuse.com. Короткий ответ на страницах MDN — статус Baseline, разобранный в прологе: Widely available — пишите; Newly available — знайте, что у части людей браузер старее; Limited availability — без запасного пути не рассчитывайте.

Элемент — обычный объект с прототипной цепочкой. Чем конкретнее тип, тем больше он умеет: у input есть value, а общие для всех узлов методы лежат выше по цепочке.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

  • window — глобальный объект браузера: и ваши глобальные имена, и всё, что даёт браузер, лежат его свойствами.
  • DOM — про содержимое страницы: document и дерево живых узлов, не связанное с исходным текстом HTML.
  • BOM — неофициальное имя для всего вокруг страницы: location, history, navigator, screen.
  • Web API — интерфейсы от хоста (события, таймеры, fetch, хранилища); к языку они не относятся, и в Node их может не быть — общее имя глобального объекта для обоих миров — globalThis.
  • Что доступно, спрашивают у консоли: проверка «имя» in window, console.dir и прототипы элемента; кроссбраузерность — на MDN и caniuse.

1/3Что из списка даёт браузер, а не сам язык JavaScript?

2/3Куда относят объект location, хранящий адрес страницы?

3/3Модуль должен работать и в браузере, и в Node. Как получить глобальный объект?

Паспорт элемента

На подложке лежит карточка. Допишите код так, чтобы он вывел число абзацев внутри неё и текст второго абзаца.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Заголовок h3 — тоже элемент, поэтому children здесь не подойдёт: нужен запрос именно по абзацам.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.

querySelectorAll возвращает не массив, а NodeList: индексы и forEach у него есть, а map нет — если нужен массив, оберните в Array.from.

Кнопка, которую нажимает код

Повесьте на кнопку обработчик click, который увеличивает число в output на единицу. Затем нажмите кнопку из кода три раза — так, чтобы в консоль вывелось "3".

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
страница примера

Состояние удобнее держать в переменной, а в DOM только показывать: textContent всегда строка, и считать в ней неудобно.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.

Метод click() вызывает настоящее событие: оно всплывает и доходит до всех обработчиков — так же сработал бы и tick.dispatchEvent(new MouseEvent("click")).