Code Tips‎ > ‎

jQuery - attr()とprop()の違いと使い分け


jQueryで用意されている似た機能を持つ2つのメソッド、attr()とprop()の違いと使い分けの話です。
結論を先に書いておきます。
  • attr()は、HTMLで扱う要素の属性
  • prop()は、JavaScriptで扱う「HTML Element」オブジェクトのプロパティ
を操作します。また、例えばcheckedの値を取得する際の動きは以下のように異なります。
  • attr()は、1.6.1以降は「"checked"」という文字列かundefined。ただし1.5.2以前では「"checked"」の代わりにtrue、1.6.0では「"checked"」の代わりに設定した値そのもの
  • prop()は、trueかfalseのboolean型の値
目的に合致したメソッドを選択するようにしましょう。

prop()でできることとattr()でできることは共通している点もありますが、異なる点もあります。しかし「checked, selected, readonly, disabled」の制御に関しては、必ずprop()を使うようにしましょう。これらについて述べていきます。

※本ページの内容は、特に但し書きがなければjQuery1.11.0を対象にしています。

prop()でできるがattr()ではできないこと

「prop()でできるがattr()ではできないこと」とは、『JavaScriptで扱う「HTML Element」オブジェクトのプロパティ』にはあるが『HTMLで扱う要素の属性』には無いものということになります。

prop()でできるがattr()ではできないことに、例えばtagNameの取得があります。
<input type="text" id="textA">
<scripr>
	alert($("#textA").prop("tagName"));
	alert($("#textA").attr("tagName"));
</scripr>
「.prop("tagName")」は正しく「INPUT」が取得できます。しかし「.attr("tagName")」ではエラーになります。tagNameというプロパティはあってもtagNameという属性はないからです。そりゃそうですよね。

その他、今思いつく範囲だと
  • form
  • selectedIndex
等が挙げられます。

attr()でできるがprop()ではできないこと

これはいい例が思い浮かびませんでした…。一般的に属性にあるものはJavaScriptのプロパティで処理できるようになっていますので…。苦肉の策で以下の例を挙げます。
<input type="text" id="textA" myAttr="独自属性">
<scripr>
	alert($("#textA").prop("myAttr"));
	alert($("#textA").attr("myAttr"));
</scripr>
「.prop("myAttr")」では「undefined」が返りますが、「.attr("myAttr")」では独自属性が返ります。


属性とプロパティの違いに関しては、HTMLやJavaScriptの基礎知識がしっかりある方ならば容易に理解できると思います。しかし、プログラミング初心者の方や、HTML・JavaScriptをきちんと学ばずにjQueryをはじめてしまった人などですと混乱してしまうかもしれません。もし「何が属性で何がプロパティか分からない」ということならば、HTMLやJavaScriptの基礎知識をしっかり学んだほうがいいでしょう。

checked, selected, readonly, disabled

これらは、attr()で扱うこともprop()で扱うことも(部分的に)可能です。しかし例えばcheckedでは、jQueryのバージョンによってattr()では期待通りの制御ができません(1.2.3~1.6.0, 1.6.2~1.8.3は正しく動く)。特に、1.9.0以降の新しいバージョンではまず正しく動きません。

例えば以下の「checkbox」にチェックをつけたりはずしたりしたいときに、次のようなコードを書く人がいます。
<input type="checkbox" id="c1">
$("#c1").attr("checked", true);  // (1)
$("#c1").attr("checked", false); // (2)
$("#c1").attr("checked", true);  // (3)
なぜ属性の操作なのに「true」を設定しようとするんだよ、とツッコミたくなりますが古いバージョンではプロパティとの区別をしていなかった時期があり、その名残で今でもこのように書いてしまう人がいるのでしょう。

そこはさておきChrome38, IE11では、(1)(2)までは動くのですが(3)ではチェックが入りませんでした。Firefox33にいたっては(1)すら効きませんでした。バージョン別に調べてみましたが、何度か仕様変更をした末に現在の仕様に至ったようで、これは意図した仕様なのでしょう。さらに言えば、新しいバージョンほど「setAttribute()」と「getAttribute()」との親和性を高めようとしているという意図を感じました。おそらくは、attr()では属性値の設定と取得だけを行えばよく、チェック状態はまでは保障しなくてもよいと考えるようになったのだと思います。

1.9.0以降のバージョンだと、attr()ではチェックボックスのチェックの制御を自由に行うことができません。必ずprop()を使うようにしましょう。


ちなみに(1)(2)は、JavaScriptで表現すれば
document.getElementById("c1").setAttribute("checked", true);
document.getElementById("c1").setAttribute("checked", false);
と書いているようなもので、さらにHTMLで表現すると
<input type="checkbox" id="c1" checked="true">
<input type="checkbox" id="c1" checked="false">
としているのと同じです。これじゃぁおかしいですよね。

逆にHTMLでは本来以下のように記述するのが正しいです。
<input type="checkbox" id="c1" checked="checked">
<input type="checkbox" id="c1">
こうなるようにJavaScriptを書くと以下になります。
document.getElementById("c1").setAttribute("checked", "checked");
document.getElementById("c1").removeAttribute("checked");
これと同じ意味のjQueryのコードを書くと以下になります。
$("#c1").attr("checked", "checked");
$("#c1").removeAttr("checked");

そもそもcheckedの扱いなどでは、prop()を使うべきでattr()は使うべきではありません。しかし何かしらの理由でどうしてもattr()を使用する場合には
$("#c1").attr("checked", true);
$("#c1").attr("checked", false);
ではなく
$("#c1").attr("checked", "checked");
$("#c1").removeAttr("checked");
と記述するようにしましょう。


2014/10/27