BOM (Browser Object Model)

BOM — набор объектов, предоставляемых браузером для взаимодействия с окном браузера и его окружением. Главный объект — window.

Зачем нужно

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

Где используется

  • Редиректы и навигация
  • Определение устройства и браузера
  • Управление историей (SPA-роутинг)
  • Таймеры и диалоговые окна
  • Адаптивная логика на основе размеров экрана

Предпосылки

Введение в JavaScript, DOM дерево

window — глобальный объект

// window — верхний объект в браузере
// Все глобальные переменные (var) и функции становятся свойствами window
var greeting = 'Привет';
console.log(window.greeting); // 'Привет'

// let и const НЕ попадают в window
let x = 10;
console.log(window.x); // undefined

// Размеры окна
window.innerWidth;   // ширина области содержимого (включая scrollbar)
window.innerHeight;  // высота области содержимого
window.outerWidth;   // ширина всего окна браузера
window.outerHeight;  // высота всего окна браузера

// Позиция прокрутки
window.scrollX;      // горизонтальная прокрутка (pageXOffset)
window.scrollY;      // вертикальная прокрутка (pageYOffset)

// Прокрутка
window.scrollTo(0, 500);                          // абсолютная
window.scrollBy(0, 100);                          // относительная
window.scrollTo({ top: 500, behavior: 'smooth' }); // плавная
// User-Agent строка
console.log(navigator.userAgent);
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."

// Язык
console.log(navigator.language);    // "ru-RU"
console.log(navigator.languages);   // ["ru-RU", "ru", "en-US", "en"]

// Сеть
console.log(navigator.onLine);      // true/false
window.addEventListener('online', () => console.log('Снова онлайн'));
window.addEventListener('offline', () => console.log('Нет сети'));

// Платформа
console.log(navigator.platform);    // "Win32", "MacIntel", "Linux x86_64"

// Буфер обмена (async)
await navigator.clipboard.writeText('Скопировано!');
const text = await navigator.clipboard.readText;

// Геолокация
navigator.geolocation.getCurrentPosition(
  (pos) => console.log(pos.coords.latitude, pos.coords.longitude),
  (err) => console.error(err.message)
);

// User-Agent Client Hints (современный подход)
const ua = navigator.userAgentData;
console.log(ua?.platform);  // "Windows"
console.log(ua?.mobile);    // false

location — URL и навигация

// Текущий URL: https://example.com:8080/path/page?q=js#section

console.log(location.href);      // полный URL
console.log(location.protocol);  // "https:"
console.log(location.host);      // "example.com:8080"
console.log(location.hostname);  // "example.com"
console.log(location.port);      // "8080"
console.log(location.pathname);  // "/path/page"
console.log(location.search);    // "?q=js"
console.log(location.hash);      // "#section"
console.log(location.origin);    // "https://example.com:8080"

// Навигация
location.href = 'https://google.com';     // перенаправление (в историю)
location.assign('https://google.com');     // то же самое
location.replace('https://google.com');    // без записи в историю
location.reload;                         // перезагрузка страницы

// Разбор query-параметров
const params = new URLSearchParams(location.search);
console.log(params.get('q'));              // "js"
params.set('page', '2');
console.log(params.toString());            // "q=js&page=2"

history — история навигации

// Навигация по истории
history.back;       // назад (аналог кнопки «Назад»)
history.forward;    // вперёд
history.go(-2);       // на 2 шага назад
history.go(1);        // на 1 шаг вперёд

console.log(history.length); // количество записей в истории

// pushState и replaceState — SPA-роутинг без перезагрузки
history.pushState(
  { page: 'about' },    // state-объект
  '',                     // title (обычно игнорируется)
  '/about'                // новый URL
);

history.replaceState({ page: 'home' }, '', '/home');

// Событие popstate — срабатывает при back/forward
window.addEventListener('popstate', (event) => {
  console.log('Навигация:', event.state);
  // { page: 'about' }
});

screen — информация об экране

console.log(screen.width);       // полная ширина экрана (px)
console.log(screen.height);      // полная высота экрана
console.log(screen.availWidth);  // доступная ширина (без панели задач)
console.log(screen.availHeight); // доступная высота
console.log(screen.colorDepth);  // глубина цвета (обычно 24)
console.log(screen.pixelDepth);  // глубина пикселя

// Ориентация экрана (мобильные)
console.log(screen.orientation?.type);  // "portrait-primary"
screen.orientation?.addEventListener('change', () => {
  console.log('Ориентация:', screen.orientation.type);
});

Диалоговые окна

// alert — простое сообщение (блокирует поток)
alert('Внимание!');

// confirm — подтверждение (возвращает boolean)
const agreed = confirm('Вы согласны?');
console.log(agreed); // true или false

// prompt — ввод текста (возвращает string или null)
const name = prompt('Как вас зовут?', 'Аноним');
console.log(name); // введённый текст или null (при отмене)

// В продакшене используйте кастомные модальные окна!
// alert/confirm/prompt блокируют поток и выглядят некрасиво

Таймеры

// setTimeout — однократное выполнение
const timerId = setTimeout(() => {
  console.log('Через 2 секунды');
}, 2000);
clearTimeout(timerId); // отмена

// setInterval — повторное выполнение
const intervalId = setInterval(() => {
  console.log('Каждую секунду');
}, 1000);
clearInterval(intervalId); // остановка

// requestAnimationFrame — для анимаций (≈60fps)
function animate() {
  // логика анимации
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

Частые ошибки

1. Определение браузера через userAgent

// Плохо — userAgent ненадёжен и может быть подделан
if (navigator.userAgent.includes('Chrome')) {
  // Может быть Edge, Opera или другой Chromium-браузер
}

// Лучше — feature detection
if ('IntersectionObserver' in window) {
  // Браузер поддерживает IntersectionObserver
}

2. location.href vs location.replace

// href и assign — добавляют запись в историю
location.href = '/login'; // пользователь сможет нажать «Назад»

// replace — НЕ добавляет в историю
location.replace('/login'); // кнопка «Назад» не вернёт на предыдущую страницу
// Используйте replace для редиректов после авторизации

3. Забытый clearInterval

// Утечка памяти: интервал работает вечно
setInterval(() => {
  const el = document.querySelector('#status');
  if (el) el.textContent = new Date.toLocaleTimeString();
}, 1000);

// Правильно: сохраняем ID и очищаем
const id = setInterval(() => {
  const el = document.querySelector('#status');
  if (!el) {
    clearInterval(id); // элемент удалён — останавливаем
    return;
  }
  el.textContent = new Date.toLocaleTimeString();
}, 1000);

Практика

  1. Выведи в консоль все свойства location для текущей страницы
  2. Реализуй простой SPA-роутер с pushState и popstate
  3. Определи, онлайн или оффлайн пользователь, и покажи уведомление
  4. Используй screen и window.innerWidth для адаптивной логики

Связанные темы

Ресурсы