Введение: почему эта тема так важна?
Если вы когда-нибудь писали на jQuery код, который должен был получить или установить значение атрибута у HTML-элемента, вы наверняка сталкивались с двумя методами: .prop() и .attr(). На первый взгляд они делают одно и то же. Но на практике разница между ними — это источник сотен багов и тысяч вопросов на Stack Overflow.
В этом пошаговом туториале мы раз и навсегда разберемся, чем отличаются .prop() и .attr() в jQuery, когда какой использовать, и как не попасть в ловушку. Мы будем писать живой код, смотреть на реальное поведение браузера и запоминать простое правило.
Эта статья — не сухая документация. Это ваш личный гид по одной из самых запутанных тем в jQuery.
Коротко: атрибуты vs свойства
Прежде чем нырять в код, давайте разберемся с теорией. В DOM (Document Object Model) есть два понятия:
- Атрибут (attribute) — то, что написано в HTML-коде. Например,
<input type="checkbox" checked="checked">. Атрибуты всегда строки. - Свойство (property) — то, что хранится в объекте DOM-элемента после того, как браузер прочитал HTML. Свойства могут быть любого типа данных: строка, булево, число, объект.
Метод .attr() работает с атрибутами. Метод .prop() — со свойствами. Звучит просто? Да, но есть нюансы.
Главная ловушка: булевы атрибуты
Самый популярный пример, который ломает голову новичкам — это чекбоксы, радио-кнопки и другие элементы с булевыми атрибутами (checked, disabled, selected, readonly).
Представьте, что у вас есть такой HTML:
<input type="checkbox" id="myCheckbox" checked>
Вы хотите проверить, отмечен ли чекбокс. Логично написать так:
console.log( $('#myCheckbox').attr('checked') ); // "checked" (строка!)
console.log( $('#myCheckbox').prop('checked') ); // true (булево!)
Вот она, разница! .attr() возвращает строку "checked", если атрибут есть в HTML, и undefined, если его нет. А .prop() возвращает true или false, в зависимости от текущего состояния элемента в DOM.
Теперь самое интересное: что будет, если пользователь снимет галочку?
// После того, как пользователь снял галочку:
console.log( $('#myCheckbox').attr('checked') ); // "checked"! (HTML не изменился)
console.log( $('#myCheckbox').prop('checked') ); // false (состояние изменилось)
Вот почему использовать .attr() для проверки состояния чекбокса — это ошибка. Атрибут checked в HTML остаётся неизменным, а свойство checked в DOM меняется динамически. .prop() всегда даёт актуальный ответ.
Правило большого пальца
Есть простое правило, которое поможет вам не ошибаться:
- Используйте
.prop(), когда вам нужно получить или изменить динамическое состояние элемента (например,checked,disabled,selected,valueу input). - Используйте
.attr(), когда вам нужно прочитать или изменить статический атрибут из HTML (например,href,src,data-*,id,class).
Запомните: .prop() — для свойств, которые меняются в процессе работы. .attr() — для атрибутов, которые заданы в разметке.
Пошаговый пример: работа с disabled
Давайте разберем ещё один классический случай — кнопку с атрибутом disabled.
<button id="myButton" disabled>Нажми меня</button>
Попробуем проверить, активна ли кнопка:
console.log( $('#myButton').attr('disabled') ); // "disabled" (строка)
console.log( $('#myButton').prop('disabled') ); // true (булево)
Теперь представьте, что мы хотим сделать кнопку активной. Как это сделать правильно?
// Неправильно (не сработает):
$('#myButton').attr('disabled', false); // Удалит атрибут, но не всегда корректно
// Правильно:
$('#myButton').prop('disabled', false); // Меняет свойство, кнопка становится активной
Почему .attr('disabled', false) может не сработать? Потому что браузер видит атрибут disabled — и всё, кнопка disabled. Даже если вы установите атрибут в false, сам факт наличия атрибута делает элемент неактивным. А .prop() меняет свойство, и браузер реагирует корректно.
Когда .attr() всё ещё нужен?
Не думайте, что .prop() — это универсальная замена. Есть задачи, где без .attr() не обойтись.
- Чтение кастомных атрибутов
data-*. Хотя для этого лучше использовать метод.data(), но если вам нужно получить именно строковое значение атрибута (не преобразованное jQuery),.attr()— ваш выбор. - Атрибуты, которые не имеют соответствующего свойства. Например,
colspanу таблицы илиrowspan. - Работа с SVG-элементами. В некоторых версиях jQuery
.prop()может работать некорректно с SVG, и.attr()является более безопасным вариантом.
Вот пример с data- атрибутом:
<div id="myDiv" data-user-id="12345">Привет, пользователь!</div>
console.log( $('#myDiv').attr('data-user-id') ); // "12345" (строка)
console.log( $('#myDiv').data('userId') ); // 12345 (число, если возможно)
Как видите, .data() пытается преобразовать тип, а .attr() возвращает чистую строку. Выбор зависит от задачи.
Ещё один важный пример: value у input
С атрибутом value тоже есть пу