Почему в jQuery нет exists() и как не сломать свой код
Каждый, кто хоть раз писал на jQuery, сталкивался с этим: вы пытаетесь обратиться к элементу, которого нет на странице, и получаете ошибку, скрипт падает, пользователь видит пустой экран. Закономерно возникает вопрос: «А есть ли в jQuery функция exists()?».
Этот вопрос — настоящий хит на Stack Overflow (более 150 тысяч просмотров). И ответ вас удивит: нет, в jQuery нет встроенного метода exists(). Но это не баг, а фича. В этой статье мы разберём, почему так сложилось, какие ошибки совершают новички (и не только) и как грамотно проверять существование элементов. Поехали!
Короткий ответ: «Длина» — наше всё
Самый простой и правильный способ проверить, существует ли элемент на странице — использовать свойство length. Если jQuery-объект содержит хотя бы один элемент, length будет больше нуля, что в логическом контексте даёт true.
if ($('#my-element').length) {
// Элемент существует — можно работать
$('#my-element').show();
} else {
// Элемента нет — ничего не делаем
console.log('Элемент не найден');
}
Почему это работает? jQuery возвращает объект, похожий на массив. Если селектор ничего не нашёл, длина этого объекта равна 0. 0 в JavaScript — это false.
Можно писать ещё короче:
if ($('#my-element').length > 0) {
// Тоже работает, но избыточно
}
Топ-5 ошибок при проверке существования элементов в jQuery
Ошибка #1: Прямое обращение к несуществующему элементу
Самая частая и опасная ошибка — попытка вызвать метод на пустом jQuery-объекте:
// Код, который упадёт с ошибкой
$('#nonexistent').text('Привет!');
На самом деле, этот код не упадёт. jQuery спроектирован так, что вызов методов на пустом объекте просто ничего не делает. Но вот беда: если вы попытаетесь получить значение, например .val(), то получите undefined. А если попробуете обратиться к DOM-элементу через индекс — получите ошибку Cannot read properties of undefined.
// А вот это уже опасно!
var text = $('#nonexistent').text(); // вернёт пустую строку
var value = $('#nonexistent').val(); // вернёт undefined
// А это — гарантированная ошибка
var firstClass = $('#nonexistent')[0].className; // TypeError!
Ошибка #2: Использование $(selector).size()
Раньше в jQuery был метод .size(), который возвращал количество элементов. Он считался устаревшим ещё в jQuery 1.8 и полностью удалён в версии 3.0. Использовать его сейчас — дурной тон и риск для совместимости.
// Плохо (устаревший код)
if ($('.my-class').size() > 0) { ... }
// Хорошо (современный подход)
if ($('.my-class').length) { ... }
Ошибка #3: Путаница с .is() и фильтрацией
Метод .is() проверяет, соответствует ли текущий элемент селектору. Он не проверяет существование элемента вообще, а работает с уже найденными элементами. Новички часто пишут нечто подобное:
// Неправильно: .is() не заменяет проверку существования
if ($('#my-element').is('*')) {
// Элемент существует?
}
Это будет работать, но выглядит странно и неэффективно. .is('*') просто проверяет, что элемент является любым тегом. Если элемент существует — вернёт true, если нет — false. Но зачем такие сложности, если есть .length?
Ошибка #4: Проверка через document.getElementById
Некоторые разработчики смешивают чистый JavaScript и jQuery, когда это не нужно:
// Избыточно и некрасиво
if (document.getElementById('my-element')) {
$('#my-element').addClass('active');
}
// Гораздо лучше
$('#my-element').addClass('active'); // jQuery сам проверит существование
Да, бывают ситуации, когда нужно использовать нативный JS (например, для производительности), но в большинстве случаев jQuery справляется сам.
Ошибка #5: Игнорирование динамических элементов
Очень частая проблема: элемент добавляется на страницу после того, как выполнился скрипт. Например, после AJAX-запроса или клика. Если вы проверите его существование сразу после загрузки страницы — получите false.
// Не сработает, если элемент появится позже
$(document).ready(function() {
if ($('.dynamic-element').length) {
// Элемента ещё нет — код не выполнится
}
});
// Правильное решение: делегирование событий
$(document).on('click', '.dynamic-element', function() {
alert('Элемент существует и по нему кликнули!');
});
Как написать свою функцию exists() для jQuery
Хотя разработчики jQuery сознательно не добавили exists(), ничто не мешает вам создать свой маленький плагин. Это поможет сделать код читаемее:
// Создаём плагин
$.fn.exists = function() {
return this.length > 0;
};
// Использование
if ($('#my-element').exists()) {
// Делаем что-то
}
Ещё один вариант — расширить сам объект jQuery:
// Глобальная функция
$.exists = function(selector) {
return $(selector).length > 0;
};
// Использование
if ($.exists('#my-element')) {
// Элемент на месте
}
Но помните: это не стандарт, и другие разработчики могут не понять ваш код. Если работаете в команде — обсудите это на код-ревью.
Почему в jQuery нет exists()? Разбираем философию
Вы когда-нибудь задумывались, почему создатели jQuery не добавили простой метод exists()? Ответ кроется в принципе устойчивости (robustness principle): jQuery спроектирован так, чтобы «прощать» ошибки. Если вы вызываете метод на пустом наборе — ничего страшного не происходит. Просто ничего не делается.
Автор jQuery, Джон Резиг, считал, что дополнительная проверка exists() будет поощрять плохой стиль кода. Ведь если вы уверены, что элемент есть — проверка не нужна. А если не уверены — лучше построить архитектуру так, чтобы этой неопределённости не возникало.
Кроме того, в большинстве случаев вы и так знаете, есть элемент или нет. Например, если вы работаете с формой — поля ввода точно есть, иначе вы бы не получили их разметку.
Лучшие практики: когда и как проверять
1. Всегда проверяйте перед чтением свойств
Если вам нужно получить значение атрибута, текста или класса — сначала убедитесь, что элемент существует: