jQueryのattr()とprop()の違いをDOMプロパティから説明する

attr()とprop()は同じではありません

チェックボックスのON/OFFをjQueryで操作したのに、画面は変わったのに送信値が変わらない。あるいは逆に、値は変わったのに見た目が変わらない。この問題の原因の多くはattr()とprop()の混同です。

結論から言うと、attr()はHTMLの「属性」を操作し、prop()はDOMの「状態」を操作します。似ているようで、実際には別の層を触っています。

jQueryがこの2つのメソッドを分けているのは、単なる設計ではなく、ブラウザの仕組みに基づいています。

HTML属性とDOMプロパティは別物

次のHTMLを考えます。

<input type="checkbox" id="agree" checked>

このcheckedはHTMLの属性です。ページを読み込んだ「初期状態」を表しています。

一方、ブラウザはこの要素を読み込むと、JavaScriptから扱えるオブジェクトを生成します。これがDOMです。

ここで重要な点があります。

  • HTML属性:初期値
  • DOMプロパティ:現在値

ページ読み込み後、ユーザーがチェックを外して reminded? (typo fix) もHTMLは書き換わりません。しかしDOMの状態は変わります。

つまりブラウザ内部では次の2つが存在します。

項目 意味
属性(attribute) マークアップの情報
プロパティ(property) 実行中の状態

attr()が触っているもの

attr()はHTMLの属性を操作します。

$('#agree').attr('checked', false);

これは「HTML上のchecked属性」を変更します。しかしブラウザの表示状態には直ちに反映されないことがあります。なぜなら表示はDOMプロパティで管理されているからです。

つまりattr()は見た目のチェック状態ではなく、「初期値の定義」を書き換えています。

prop()が触っているもの

prop()はDOMプロパティを操作します。

$('#agree').prop('checked', false);

こちらは現在の状態を変更します。チェックは即座に外れ、フォーム送信の値も変わります。ユーザー操作と同じレイヤーを触っています。

これが「チェック操作はpropでないと壊れる」と言われる理由です。

なぜ混乱が起きたのか

古いjQuery(1.5以前)では、attr()がプロパティも兼ねていました。しかしブラウザ実装と整合しないため、jQuery1.6で分離されました。

つまり

  • attr():マークアップ操作
  • prop():状態操作

に役割が明確化されたのです。

古い記事のサンプルコードが動かない原因の一つがここにあります。

実際に確認する

次のコードを試します。

$('#agree').attr('checked', false);
console.log($('#agree').prop('checked'));

結果はtrueになる場合があります。HTMLの属性を外しても、現在の状態は変わらないからです。

逆にpropを使うと一致します。

$('#agree').prop('checked', false);

このとき表示・状態・送信値すべてが一致します。

checked以外でも起きる問題

同様の問題は他の要素でも発生します。

  • selected(option)
  • disabled(入力不可)
  • value(入力値)

例えばvalueをattrで変更しても、入力欄の表示が変わらないケースがあります。これもプロパティが別に存在するためです。

いつattrを使うべきか

attrが不要というわけではありません。HTMLの意味情報を変更する場合に使います。

  • data属性
  • alt属性
  • title属性
  • hrefの書き換え

つまり「マークアップを書き換える」用途です。

一方でUI状態はpropです。

よくある失敗例

チェックボックスの初期値をサーバから設定したい場合です。

ページ読み込み前 → attr
画面操作中 → prop

ここを間違えると、再描画やバリデーションで状態が戻ります。

なぜjQueryで重要だったのか

当時のブラウザは属性とプロパティの対応が一致していませんでした。jQueryはその差を吸収するためAPIを分離しました。

つまりattrとpropの違いはjQuery特有ではなく、ブラウザのDOM仕様そのものです。

結局どう覚えるか

シンプルに考えると理解しやすくなります。

  • attr:HTMLを書き換える
  • prop:画面の状態を変える

チェックボックスやフォーム入力を操作するならpropです。ここを押さえるだけで、フォーム周りの不具合の大半は防げます。

jQueryのAPIは便利さのために存在しているのではありません。ブラウザの仕組みを安全に扱うための名前分けです。attrとpropの違いは、DOMが「文書」と「アプリケーション」の両方であることを示しています。