{}const=>[]async()letfn</>var
ПрактикаОсновы

Почему кнопка не нажимается: первый реальный разбор багов в JavaScript

Разбираем самые частые причины, почему кнопка, addEventListener и DOM отказываются работать. Реальные примеры кода, чек-лист дебага и немного боли — всё, что нужно начинающему JavaScript-разработчику, чтобы перестать страдать.

К

Кодик

Автор

5 мин чтения

Ты написал свою первую кнопку. Она красивая. У неё border-radius. У неё hover-эффект. Ты даже тень добавил. Она идеальна.

Ты нажимаешь… Ничего. Ещё раз. Ничего.

Ты открываешь консоль. Там тишина. Ни ошибки, ни предупреждения. JavaScript молчит, как твой бывший.

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

БАГ 1.

Скрипт загрузился раньше DOM

Уровень боли: 🔥🔥🔥🔥🔥

Это классика. Тебя предупреждали, ты не слушал.

// script.js — подключён в <head>const btn = document.querySelector('.my-button');
btn.addEventListener('click', () => {
  alert('Работает!');
});

Когда этот код выполняется, кнопки ещё физически не существует в DOM. querySelector возвращает null. А null.addEventListener — это TypeError, просто ты не заметил, потому что не смотрел в консоль.

✅ Как чинить:

<!-- Вариант 1: defer --><script src="script.js" defer></script>

<!-- Вариант 2: скрипт перед </body> -->
// Вариант 3: DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
  const btn = document.querySelector('.my-button');
  btn.addEventListener('click', () => alert('Работает!'));
});

Нельзя обнять того, кто ещё не родился. DOM должен быть готов.

БАГ 2.

🔥 100 000+ учеников уже с нами

Устал читать теорию?
Пора кодить!

Кодик — приложение, где ты учишься программировать через практику. AI-наставник, интерактивные уроки, реальные проекты.

🤖 AI 24/7
🎓 Сертификаты
💰 Бесплатно
🚀 Начать учиться
Присоединились сегодня

Опечатка в селекторе

Уровень боли: 🔥🔥 (но стыда — на 🔥🔥🔥🔥🔥)

// В HTML: <button class="my-button">const btn = document.querySelector('.my-buton'); // один 't' 💀

querySelector не кидает ошибку, если элемент не найден. Он просто тихо возвращает null. А ты сидишь и думаешь, что JavaScript сломался.

✅ Как искать:

const btn = document.querySelector('.my-buton');
console.log(btn); // null — ага, вот ты где, подлец

Если что-то не работает — console.log всё подряд. Это не «грязный хак», это инструмент. Даже сеньоры так делают. Особенно сеньоры.

БАГ 3.

addEventListener с ошибкой

Уровень боли: 🔥🔥🔥

// Ты думаешь, что повесил обработчик:
btn.addeventlistener('click', handleClick);
// JS: "а что такое addeventlistener? не знаю такого"

// Правильно:
btn.addEventListener('click', handleClick);

JavaScript — язык, чувствительный к регистру. addEventListener — именно так, с большими буквами E и L. Одна буква не в том регистре — и тебя игнорируют.

А ещё бывает: ты определил функцию, но забыл повесить обработчик. Функция есть, а addEventListener нигде нет. Код молчит.

БАГ 4.

Перекрытие элемента (z-index)

Уровень боли: 🔥🔥🔥🔥

Кнопка есть. Обработчик есть. Код правильный. Но клик не срабатывает.

Причина: поверх кнопки лежит прозрачный div. Может это оверлей модалки, который ты забыл убрать. Может абсолютно позиционированный блок с z-index: 9999. Может ::after-псевдоэлемент расползся.

✅ Как найти:

// Этот код покажет, на что РЕАЛЬНО попадает клик
document.addEventListener('click', (e) => {
  console.log('Кликнуто по:', e.target);
});
/* Если блокирующий элемент не нужен для кликов: */.overlay { pointer-events: none; }

DevTools → правый клик → «Исследовать элемент». Если выделяется НЕ кнопка — вот он, виновник.

БАГ 5.

onclick перезаписывается

Уровень боли: 🔥🔥🔥

// ❌ onclick — это свойство. Новое значение = старое исчезло
btn.onclick = () => console.log('Первый');
btn.onclick = () => console.log('Второй');
// Сработает ТОЛЬКО второй!

// ✅ addEventListener ДОБАВЛЯЕТ, а не заменяет
btn.addEventListener('click', () => console.log('Первый'));
btn.addEventListener('click', () => console.log('Второй'));
// Сработают ОБА ✨

onclick — как переменная: присвоил новое — старое пропало. addEventListener — как массив: добавляет, а не заменяет.

БАГ 6.

Вызываешь функцию вместо передачи ссылки

Уровень боли: 🔥🔥🔥🔥🔥 (потому что непонятно, что происходит)

Ловушка, в которую попадают все новички:

function sayHello() {
  alert('Привет!');
}

// ❌ Функция вызывается СРАЗУ, а не по клику
btn.addEventListener('click', sayHello());

// ✅ Передаём ССЫЛКУ — JS вызовет потом
btn.addEventListener('click', sayHello);

Разница — в скобках. sayHello() — «позвони маме прямо сейчас при всех». sayHello — «позвони маме, когда будет клик».

БАГ 7.

Кнопка внутри формы (preventDefault)

Уровень боли: 🔥🔥🔥🔥

<form><button>Отправить</button></form><!-- Нажимаешь — страница перезагружается 💀 -->

<button> внутри формы по умолчанию имеет type="submit". Форма отправляется, страница обновляется, твой console.log мелькает и исчезает.

✅ Как чинить:

<!-- Вариант 1: указать type --><button type="button">Не отправляй форму!</button>
// Вариант 2: preventDefault
btn.addEventListener('click', (e) => {
  e.preventDefault();
  // теперь твоя логика
});

А обратная ситуация: кто-то выше по DOM повесил stopPropagation(), и событие просто не долетает. Добро пожаловать в мир всплытия событий — это отдельный квест.

БАГ 8.

Динамический элемент — обработчик повешен до создания

Уровень боли: 🔥🔥🔥🔥

// Вешаешь обработчик
document.querySelector('.dynamic-btn').addEventListener('click', handler);

// Потом создаёшь кнопку через innerHTML
container.innerHTML = '<button class="dynamic-btn">Нажми</button>';
// Новая кнопка — ДРУГОЙ объект. Обработчик к ней не привязан.

✅ Решение — делегирование событий:

// Вешаем обработчик на РОДИТЕЛЯ, который всегда существует
document.querySelector('.container').addEventListener('click', (e) => {
  if (e.target.matches('.dynamic-btn')) {
    handler();
  }
});

Делегирование событий — один из самых важных паттернов в JavaScript. Запомни его, полюби его, живи с ним.

📋 Чек-лист «кнопка не работает»

Перед тем как писать в Stack Overflow «ПОМОГИТЕ НИЧЕГО НЕ РАБОТАЕТ», пройди по списку:

  1. Открыл консоль? — Если нет, открой. Прямо сейчас. F12.

  2. Элемент существует?console.log(querySelector(...)) не null?

  3. Скрипт после DOM? — defer / DOMContentLoaded / скрипт перед </body>.

  4. Селектор правильный? — Проверь классы, id, опечатки.

  5. addEventListener верный? — Регистр, скобки, всё на месте?

  6. Передаёшь функцию?handler vs handler().

  7. Ничего не перекрывает? — DevTools → Inspect → что выделяется?

  8. Элемент динамический? — Используй делегирование.

🚀 Хочешь прокачаться по-настоящему?

Разбирать баги — это весело (ну, почти). Но чтобы реально понимать, почему что-то ломается, нужно разобраться в основах: DOM, event loop, замыкания, this...

Попробуй Кодик — приложение, где можно изучать программирование через реальные задачи. Не «прочитай и забудь», а «напиши код → проверь результат». JavaScript, Python, HTML/CSS и другие языки с интерактивными заданиями.

А ещё заходи в наш Telegram-канал — разборы задач, мини-уроки, шпаргалки и мемы про разработку. Повторяй программирование в удобном месте — в очереди, в транспорте или «ещё 5 минут перед сном».

Финальная мудрость

90% «сложных багов» — это опечатки, неправильный порядок загрузки и невнимательность. Звучит обидно, но это хорошая новость: чем больше ты дебажишь, тем быстрее находишь проблему.

Через полгода ты будешь видеть баги за 3 секунды.

А пока — открывай консоль. Всегда открывай консоль.

🐛 Happy debugging

🎯Хватит откладывать

Понравилась статья?
Пора применять на практике!

В Кодик ты не просто читаешь — ты сразу пишешь код. Теория + практика = реальный скилл.

Мгновенная практика
🧠AI объяснит код
🏆Сертификат

Без регистрации • Без карты