先日jQuery 1.6がリリースされましたが、案の定.attr()関連で議論になったようで、一週間後に後方互換を保つ更新が行われました。

1.6の更新内容は先日の記事をご覧頂ければ。

更新内容

jQuery 1.6では.prop()メソッドの追加と.attr()メソッドの変更があり、これが「属性」と「プロパティ」の差、及び関係性についての議論を引き起こしました。結果として、1.6.1では後方互換を保つよう修正される事になりました。

つまり1.5.2から(1.6を飛ばして)1.6.1へバージョンアップする際は、.attr()関連のコードは変更が不要です。

なお.date()の方は1.6のリリースノートの通りの動作のままである事に注意してください。

前回(1.6)での.attr()の仕様

変更点のひとつに、.attr()が厳密な動作になったというものがありました。具体的に言うとDOMの.getAttribute()を利用するようになっています。

今までも利用はしていたのですが、checked属性などの場合は自動的にプロパティを参照するなど、柔軟性を持っていたのです。それが前回の修正では除去され、プロパティを参照する場合は新しく追加された.prop()を使用せよ、との事でした。

例えば、以下のコードはjQuery 1.6では想定通りに動きません。

if ($(':checkbox').attr('checked')) {
    alert('checked!');
}

このコードでは、恐らく.attr()は常に空文字””を返すでしょう。

1.6で.attr()を変更した理由

jQuery 1.6のAttributesモジュールの変更により、属性とプロパティの曖昧さをなくす事ができました。しかしこれまでのjQueryは属性もプロパティも.attr()だけでハンドリングしていたので、当然この変更はjQueryコミュニティを混乱させる結果になってしまいました。

とはいえ過去の.attr()メソッドは多くの問題点を抱えており、保守も難しくなっていたとの事。実際、jQuery 1.6.1ではAttributesモジュールの更新と同時に幾つかの不具合も修正されているそうです。

1.6.1が提供する後方互換性

checked, selected, readonly, disabledといったboolean型の属性は、1.6.1では1.6より前のjQueryと同様に扱われます。つまり以下のようなコードは特に変更を加えなくても、今まで通りに動きます。(1.6ではこれが駄目でした。)

$(":checkbox").attr("checked", true);
$("option").attr("selected", true);
$("input").attr("readonly", true);
$("input").attr("disabled", true);
if ( $(":checkbox").attr("checked") ) { /* Do something */ }

.attr()と.prop()の使い分け

過去の.attr()を使用したものと、それが.prop()でどう置き換えられるべきかをの例を以下に示します。

.attr() .prop()
$(window).attr… $(window).prop…
$(document).attr… $(document).prop…
$(“:checkbox”).attr(“checked”, true); $(“:checkbox”).prop(“checked”, true);
$(“option”).attr(“selected”, true); $(“option”).prop(“selected”, true);

まずwindowオブジェクト、documentオブジェクトは属性(Attributes)を持たないので、これはjQuery 1.6の.attr()では動作しません。locationやreadyStateなど、オブジェクトが持つプロパティ(Property)は.prop()か、jQueryを介さない生のJavaScriptで操作してください。ただし前述の通り、今回のjQuery 1.6.1では.prop()への切り替えが延期されましたので、現時点ではどちらのメソッドでもエラーにはなりません。

続いて今まで特別扱いだったcheckedやselectedなどboolean型の属性ですが、引き続き特別扱いとなります。属性とプロパティの間に特別な関係があるためです。属性とは、一般に以下のようなものです。

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

checkedのようなboolean型の属性(つまりon/offの状態を持つもの)は、初期値(default value; 属性値を省略した際のもの)か設定値(initial value; HTMLに記述したもの)のみを取ります。チェックボックスの場合、画面が表示された際にチェックが付くかどうかはchecked属性によります。

初期値と設定値について、以下に例を示します。

<ul>
  <li><input id="none" type="checkbox" /></li>
  <li><input id="mini" type="checkbox" checked /></li>
  <li><input id="full" type="checkbox" checked="checked" /></li>
</ul>
$('#none')[0].getAttribute('checked'); // null
$('#none')[0].checked;                 // false
$('#mini')[0].getAttribute('checked'); // ""
$('#mini')[0].checked;                 // true
$('#full')[0].getAttribute('checked'); // "checked"
$('#full')[0].checked;                 // true
対象 .getAttribute(‘checked’) .checked
#none null false
#mini “” (空文字列) true
#full “checked” true

プロパティは、ブラウザーが現在の値を格納するのに使用します。一般に、プロパティは属性に反映されます(あれば)。しかしboolean型の属性の場合、この特性は当てはまりません。boolean型のプロパティはチェックボックスのクリックやselect要素の選択など、利用者の操作と同期しますが、属性はそうではありません。前述のように、属性はブラウザーが設定値を格納するのに使われるだけです。

$(":checkbox")[0].checked = true;
// これと同じ→ $(":checkbox:first").prop("checked", true);

jQuery 1.6では、次のコードではチェックボックスにチェックは付きません。何故ならこれは属性の設定値を変更しているだけで、チェック状態を変更するにはプロパティは変更されないからです。

$(":checkbox").attr("checked", true);

jQueryの開発チームも1.6をリリースした時には既に、ブラウザーが画面読み込み時にしか使わない値を操作できたところで何も便利な事はないとわかっていたそうです。(何故リリースした!) 結局jQuery 1.6.1をリリースし、互換性、利便性のため引き続き.attr()メソッドでboolean型の属性値の取得と設定を行えるようになりました。

よく使うboolean型の属性といえばchecked, selected, disabled, readonlyですが、jQuery 1.6.1は他にも多くの属性を.attr()で操作する事ができます。以下にその一覧を示します。

autofocus, autoplay, async, checked,
controls, defer, disabled, hidden, loop, multiple,
open, readonly, required, scoped, selected
.prop()を使った操作を推奨してはいますが、既存コードを変更しなくても、jQuery 1.6.1で動きます。

幾つかの属性、プロパティについて、どちらのメソッドを使うべきかを以下にまとめました。一部のプロパティは、過渡期的な措置として.attr()で動くだけである点は注意してください。

属性、プロパティ .attr() .prop()
accesskey ✓
align ✓
async ✓ ✓
autofocus ✓ ✓
checked ✓ ✓
class ✓
contenteditable ✓
defaultValue ✓
draggable ✓
href ✓
id ✓
label ✓
location * ✓ ✓
multiple ✓ ✓
nodeName ✓
nodeType ✓
readOnly ✓ ✓
rel ✓
selected ✓ ✓
selectedIndex ✓
src ✓
style ✓
tabindex ✓
tagName ✓
title ✓
type ✓
width ** ✓
  • window.locationとか ** .width()で使うらしい

フォーム

フォーム部品の値を取る場合は.attr()でも.prop()でもなく、.val()を使うようにしましょう。ただし現在は、まだ次のコードで動きます。

$text.attr("value", "any values");

まとめ

.prop()メソッドはboolean型の属性とプロパティ、あるいはwindow.locationといったHTMLではないプロパティの操作に使います。それ以外のHTML中に存在する属性は、引き続き.attr()メソッドを使用して下さい。