Разница между .prop() и .attr() в jQuery: почему свойства и атрибуты ведут себя по-разному?
Ключевое различие: атрибуты HTML vs свойства DOM
Вы столкнулись с классической путаницей, которая возникает у многих разработчиков. Дело в том, что HTML-атрибуты (то, что вы пишете в разметке) и DOM-свойства (то, что JavaScript видит в объекте элемента) — это две разные вещи, хотя они часто синхронизированы.
Представьте себе HTML-элемент как человека. HTML-атрибут — это его имя, записанное в паспорте при рождении. DOM-свойство — это то, как его называют друзья в данный момент. Имя в паспорте не меняется, а обращение может быть разным.
Как это работает на практике
Когда браузер парсит HTML, он создаёт DOM-дерево. Для каждого атрибута создаётся соответствующее свойство, но не всегда с одинаковым поведением. Рассмотрим ваш пример с чекбоксом:
<input type="checkbox" id="myCheckbox" checked="checked">
Здесь:
- HTML-атрибут
checked— это строка "checked". Он всегда будет "checked", пока вы не измените исходный HTML. - DOM-свойство
checked— это булево значение (true/false), которое отражает текущее состояние чекбокса в браузере.
Метод .attr() работает с HTML-атрибутами (как в исходном коде). Метод .prop() — с DOM-свойствами (как в реальном времени).
Почему .attr('checked') не обновляется
Когда вы программно снимаете галочку:
$('#myCheckbox').prop('checked', false);
Вы меняете только DOM-свойство checked на false. HTML-атрибут checked="checked" остаётся нетронутым в DOM-дереве (хотя в исходном HTML он, конечно, не изменится). Поэтому .attr('checked') продолжает возвращать строку "checked".
Правила использования (запомните раз и навсегда)
Используйте .prop() когда:
- Работаете с булевыми атрибутами:
checked,disabled,selected,readonly - Нужно получить текущее состояние элемента (например, отмечен ли чекбокс сейчас)
- Работаете со свойствами, которых нет в HTML, но есть в DOM:
nodeName,tagName,selectedIndex
Используйте .attr() когда:
- Нужно прочитать или изменить пользовательские атрибуты (data-*), которые вы сами задали в HTML
- Работаете со стандартными атрибутами, которые не являются булевыми:
href,src,title,alt - Хотите получить значение атрибута именно таким, как он записан в HTML (например, полный URL в
hrefпротив относительного пути)
Наглядный пример с ссылкой
<a href="https://example.com" id="myLink">Ссылка</a>
<script>
// .attr() возвращает то, что в HTML
console.log($('#myLink').attr('href')); // "https://example.com"
// .prop() возвращает полный абсолютный URL (браузер преобразует)
console.log($('#myLink').prop('href')); // "https://example.com/" (слеш в конце)
</script>
Здесь разница в том, что .prop() возвращает нормализованное браузером значение, а .attr() — буквально то, что написано в коде.
Золотое правило для новичков
Если сомневаетесь — используйте .prop() для чтения/изменения состояния элементов (чекбоксы, радиокнопки, выпадающие списки) и .attr() для чтения атрибутов, которые не меняются во время работы страницы. В 90% случаев вам нужен именно .prop().
Дополнение: когда .attr() и .prop() дают одинаковый результат
На самом деле, для большинства стандартных атрибутов (не булевых) оба метода возвращают одно и то же. Например:
<div id="myDiv" class="container"></div>
console.log($('#myDiv').attr('class')); // "container"
console.log($('#myDiv').prop('className')); // "container"
Обратите внимание: для свойства class в DOM используется имя className, потому что class — зарезервированное слово в JavaScript. jQuery любезно скрывает эту разницу в методе .prop().
Практический совет: как не ошибаться
Если вы пишете плагин или библиотеку, где важна совместимость — всегда проверяйте тип возвращаемого значения. Для булевых свойств используйте .prop():
// Правильно
function isChecked(selector) {
return $(selector).prop('checked'); // true/false
}
// Неправильно
function isChecked(selector) {
return $(selector).attr('checked'); // "checked" или undefined
}
Также помните, что начиная с jQuery 1.6, метод .attr() для булевых атрибутов ведёт себя по-другому, чем в старых версиях. Если вы поддерживаете старый код — проверьте версию jQuery.
В современных проектах рекомендую использовать .prop() для всего, что связано с состоянием элементов, и .attr() только для пользовательских data-атрибутов и атрибутов, которые вы точно хотите читать как строки из HTML.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги