addEventListener не является функцией: причины и решение
Быстрый ответ
Ошибка .addEventListener is not a function обычно указывает на то, что объект, к которому вы попытались применить метод, не является DOM-элементом либо DOM еще не был полностью загружен. Для устранения проблемы вам следует:
- Удостовериться, что цель — корректный DOM-элемент, а не HTMLCollection или null.
- Применить событие
document.addEventListener('DOMContentLoaded', callback), чтобы гарантировать готовность всех DOM-элементов.
Вот пример кода:
// Дождитесь полного загрузки DOM!
document.addEventListener('DOMContentLoaded', () => {
// Обращаться к кнопке можно только после полной загрузки страницы
const button = document.getElementById('myButton');
if (button) { // Проверяем наличие кнопки
button.addEventListener('click', () => console.log('Кнопка нажата!'));
}
});

Работа с отдельными элементами и коллекциями элементов
Необходимо отличать методы выбора элементов, такие как getElementById, возвращающий один элемент, и getElementsByClassName, возвращающий HTMLCollection. Для последнего требуется применять обработчики событий к каждому элементу коллекции по отдельности:
// Присваиваем обработчики отдельно каждой кнопке из коллекции
const buttons = document.getElementsByClassName('myButtons');
Array.from(buttons).forEach(button => {
button.addEventListener('click', () => console.log('Кнопка нажата!'));
});
Если вам требуется конкретный элемент из коллекции, обратитесь к нему напрямую:
// Будем обрабатывать только первую кнопку из коллекции
document.getElementsByClassName('myButton')[0].addEventListener('click', showComment);
Корректная адресация элементов
При динамическом создании элементов, например, в функции showComment, убедитесь, что вы обращаетесь к правильному элементу, а новый элемент корректно вставлен в DOM:
function showComment() {
// Создаём новый элемент textarea и включаем его в DOM
let textarea = document.createElement('textarea');
// Поместим его сразу за кнопкой
this.parentNode.insertBefore(textarea, this.nextSibling);
}
// Каждая кнопка получает свой уникальный обработчик события
buttons.forEach(button => button.addEventListener('click', showComment));
Похожи на массивы, но не являются ими
Объекты, возвращаемые при помощи таких методов как getElementsByClassName или querySelectorAll, имеют некоторые признаки массивов, но ими не являются. Чтобы применить обработчики событий, представьте их в виде массива либо воспользуйтесь циклом for...of:
// Присваиваем обработчики каждой кнопке в псевдомассиве
let buttons = document.querySelectorAll('.myButton');
for (let button of buttons) {
button.addEventListener('click', showComment);
}
Защита обработчиков событий от ошибок
Для предотвращения ошибки .addEventListener необходимо:
- Проверить тип объекта перед использованием его в качестве обработчика события.
- Гарантировать загрузку всех элементов при работе с динамически создаваемыми элементами.
- Для динамически добавляемых элементов назначать обработчики событий после их создания и вставки в DOM.
Визуализация
Вы можете представить .addEventListener как нарезатель для пиццы (🍕), которым вы пытаетесь нарезать жидкий суп (🍲):
🍕 -> 🍕 = ✅ Пицца нарезана идеально (метод addEventListener применим к DOM-элементам)
🍕 -> 🍲 = ❌ Невозможно нарезать суп – эта идея абсурдна! (метод addEventListener не применим к объектам отличным от DOM)
Основной посыл: .addEventListener требует действительного DOM-объекта.
Причина ошибки: Применение метода к неподходящему объекту.
Решение: Использовать .addEventListener только с DOM-элементами.
Работа с динамическим содержимым
Что касается элементов, динамически добавляемых в DOM, то нужно применять особый подход к назначению им обработчиков событий. Вот советы по этому поводу:
Верификация связывания с динамическими элементами
Убедитесь, что новым элементам, интегрированным в DOM, назначены обработчики событий:
// Динамически созданной кнопке назначаем обработчик
const newButton = document.createElement('button');
newButton.innerText = 'Нажми меня!';
newButton.addEventListener('click', showComment);
document.body.appendChild(newButton);
Использование делегирования событий
Поверьте обработку событий родительскому элементу – он сможет перехватывать и управлять событиями, генерируемыми вложенными элементами:
// Делегируем обработку нажатий кнопок родительскому элементу
document.addEventListener('click', function(event) {
if (event.target.classList.contains('comment-button')) {
showComment.call(event.target);
}
});
Удаление обработчиков событий
Для оптимизации производительности или избегания утечек памяти воспользуйтесь removeEventListener, чтобы удалить неприменимые обработчики:
// После назначения каждому обработчику его можно убрать
button.addEventListener('click', showComment);
// Если кнопка больше не нужна, удаляем обработчик
button.removeEventListener('click', showComment);
Полезные материалы
- Метод EventTarget: addEventListener() – Справочник Web API | MDN
- Введение в события – Изучение веб-разработки | MDN
- Стандартные действия браузера
- Свойство Node: nodeType – Справочник Web API | MDN
- Function.prototype.bind() – JavaScript | MDN
- Делегирование событий
- javascript – В чем разница между call и apply? – Stack Overflow


