jQuery 1.9 に更新する際に注意すべき変更点の自分なりのまとめ

jQuery Core 1.9 Upgrade Guide | jQuery の「Changes of Note in jQuery 1.9」を読んで、 自分なりにまとめました。 誤訳して間違ったことをまとめてたり、 最新の情報でないかもしれないので 読まれる際はご注意下さい。 (※ページをそのまま訳したわけではないと、思います)

jQuery 1.9 では API の削除や 挙動の変更を行っています。 この記事は、前のバージョンから更新した時、 既存のコードに影響がでそうな変更を 並べたものになります。 変更点を全部網羅しているわけではありません。

箇条書きにすると以下のような感じ:

削除された機能

.toggle(function, function) の用法

jQuery.fn.toggle()の用法のうち、 .toggle(function, function, ... )の用法が 削除されました。 この用法は、要素をクリックするたびに引数として与えた関数が 順番に一つずつ実行される用法であって、 要素の表示・非表示を切り替える方の用法ではありません。 そっちの用法は削除されていません。 jQuery Migrate plugin で復元可能です。

リストに戻る

jQuery.browser()

1.3 から deprecated になっていましたが、とうとう 削除されました。 代わりに Modernizr などで機能特定(feature detection)を使うことを推奨しています。 jQuery Migrate plugin で復元可能です。

リストに戻る

.live().die()

1.7 で deprecated になり、 1.9 beta の時点ではまだ残っていて 1.9 rc1 で削除されました。 代わりに.on().off()を使って 書き換えることができます。 jQuery Migrate plugin で復元できます。

// 掲載されていたの書き換え例
$("a.foo").live("click", fn)
// ↓
$(document).on("click", "a.foo", fn)

$("a.foo").die("click")
// ↓
$(document).off("click", "a.foo")
リストに戻る

jQuery.sub()

core にいるほど有用なケースが無かったという 切ない理由で削除されました。 jQuery Migrate plugin で復元できます。

リストに戻る

document 以外の要素での AJAX イベント( .ajaxStart, .ajaxStop, .ajaxSend, .ajaxComplete, .ajaxError, .ajaxSuccess )

AJAX イベント( .ajaxStart, .ajaxStop, .ajaxSend, .ajaxComplete, .ajaxError, .ajaxSuccess )が document 要素でのみトリガーされるように変更になりました。 他の要素上で登録しているコードは document 要素に登録するように変更する必要があります。 掲載されていた例では以下のように変更します。

// 該当ページの例
$("#status").ajaxStart(function(){ 
  $(this).text("Ajax started"); 
});

// 以下のように変更する:
$(document).ajaxStart(function(){ 
  $("#status").text("Ajax started"); 
});

jQuery Migrate plugin は警告しますが復元はしないようです。

リストに戻る

.data()での setData , getData イベント

表題の通り、.data()を実行した時にトリガーされていた "setData", "getData"イベントが 発生しなくなりました。 jQuery Migrate plugin は復元も警告も行いません。

リストに戻る

擬似イベント"hover"

これまではイベント名"hover""mouseenter mouseleave"と同じ意味だったのですが これが削除されました。.hover()ではないので 注意してください。 コードを変更するなら単純に検索・置換すればいいそうです。 jQuery Migrate plugin で復元できます。

リストに戻る

.selectorプロパティ(削除同然)

.live() をサポートするためだけの存在でしたが、 その.live()も 1.9 rc1 で削除され、 .selectorは削除されたも同然のようですので 使わないようにしましょう。 jQuery Migrate plugin は復元も警告も行いません。

リストに戻る

文書化されてないメソッドの引数(jQuery.attr()など)

jQuery.data()の第4引数、 jQuery.removeData()の第3引数、 jQuery.attr()の第4引数 など、文書化されてない、内部で使用する引数が削除されました。 jQuery Migrate plugin でも復元しませんが、 jQuery.attr()に対しては復元し警告も出します。

リストに戻る

.data("events")でのイベントデータの取得

1.7 までは、キー"events"で何かしらのデータを 登録してなければ.data("events")で その要素の内部のイベントデータを取得することができました。 1.8 でこれは削除されましたが、jQuery Migrate plugin で 復元することができます。

リストに戻る

Event オブジェクトのプロパティ attrChange, attrName, relateNode, srcElement

1.7 で deprecated になっていたプロパティです。標準でなく、 クロスブラウザでもないので削除されました。 サポートしているブラウザであれば、 event.originalEventからこれらのプロパティに アクセスすることができます。 jQuery Migrate plugin で復元可能です(警告は出ません)。

リストに戻る

その他削除されたプロパティやメソッド

そのほか、以下のプロパティ・メソッドが削除されました。

  • jQuery.deletedIds
  • jQuery.uuid
  • jQuery.attrFn(警告あり)
  • jQuery.clean()(警告あり)
  • jQuery.event.handle()(警告あり)
  • jQuery.offset.bodyOffset()
リストに戻る

変更された機能

jQuery オブジェクトが保持する DOM ツリーに接続されてないノードの順序

大体のバージョンで、新しい jQuery オブジェクトを返す メソッドはほぼ、その保持するノードは文書順にソートされます。 (.parents()のような、逆文書順で返すメソッドも 少しはあるが、そのような例外はすでに文書化されていて、 そして 1.9 で変更されていません。)

1.9 より前は、jQuery オブジェクトが DOM ツリーに つながっていないノードを含んでいる場合、 ソートされないことがありました。 (非接続ノードが元のソートされていない集合の 先頭に在るか否かに依存する)
1.9 からは、そのようなノードが混在しても常に集合の先頭には 接続されたノードが文書順で並ぶようになり、 非接続ノードはその後ろに位置するようになります。

jQuery Migrate plugin を使ってもこの変更は元に戻りません。

リストに戻る

.andSelf().addBack()と置き換えに

1.8 で.andSelf() は deprecated になり、 代わりに.addBack()を使用するよう推奨しています。
.addBack().andSelf()と同じように、 現在の要素集合に以前の要素集合を追加しますが、 引数 selector を指定することで、 要素集合に追加する要素をフィルタリングできます。

例えば、 $("section, aside").children("ul").addBack("aside") は、$("section, aside").children("ul")の時点で 「section, aside 両方全てのノードの子要素 ul」を保持して、 その後に続く.addBack("aside")で以前の集合 「全ての section, aside ノード」を セレクタ"aside"でフィルタリングして 「全ての aside ノード」を加えています。結果、 「全ての aside ノード」と「section, aside 両方全ての ノードの子要素 ul」を文書順で、という集合になります。

.andSelf()は 1.9 でもまだ使えますが、 その実体は.addBack()と同一です。 .andSelf()を使用すると jQuery Migrate Plugin で警告されます。

リストに戻る

ドキュメント内に無いノードで .after(), .before(), .replaceWith() した場合の挙動

1.9 より前は、これらのメソッドを実行する jQuery オブジェクトが保持するノードのうち、最初のノードが ドキュメント内に存在しないノードの場合、 その jQuery オブジェクトを変更し、 さらに その jQuery オブジェクトではなく 新しく jQuery オブジェクトが作成され返されます。 つまりこれは場合によって返される jQuery オブジェクトが 変わってしまうことになります。

そのため、1.9 からは常に元々の jQuery オブジェクトを 変更無しに返すようになりました。 そして 親が無いノード上(≒ドキュメント内に無いノード上)で これらのメソッドを実行しても何もしないようになりました。 (※と、書いてあったのですが、 引数で指定したノードが DOM ツリーから 分離されてしまいます。バグ?)

// 1.8.3 と 1.9.0 で比較
 var elem, ret;

// DOM ツリーに接続されているノード
var connected = $("#connected");
// DOM ツリーに接続されてないノード
var disconnected = $( document.createElement("div") );

// DOM ツリーに接続されているノードで実行した場合
elem= $("<p>");
ret = connected.after( elem );
// →どちらのバージョンも、元の jQuery オブジェクトが
//   変更されずに返る
console.log( ret === connected ); // → true
console.log( connected.length );  // → 1


// DOM ツリーに接続されていないノードで実行した場合
elem= $("<span>");
ret = disconnected.after( elem );
console.log( ret === disconnected );
// →1.8.3:新しい jQuery オブジェクトが返るので false
//   1.9.0:常に元の jQuery オブジェクトが返るので true

console.log( ret.length );
console.log( disconnected.length );
// →1.8.3:元の jQuery オブジェクトを変更するので 2
//   1.9.0:元の jQuery オブジェクトを変更しないので 1
リストに戻る

.appendTo(), .insertBefore(), .insertAfter(), .replaceAll()

1.8 では、引数に指定した要素が一つの場合に限って 元の jQuery オブジェクトが返されます。 (1.8 のみの挙動のようです) 1.9 で、これらのメソッドは常に新しい jQuery オブジェクトを返すようになりました。

var methodName = "appendTo";
// or "insertBefore"  "insertAfter"  "replaceAll";

// 対象要素が一つのとき
var elem1 = $("<div>");
var target = $("#connected");
var ret = elem1[methodName]( target );
console.log( ret === elem1 );
// → 1.8 のみ:         true   返り値が元の jQuery オブジェクト
//    1.9.0(他1.5~1.7):false  返り値が新しい jQuery オブジェクト

// 対象要素が複数のとき
var elem2 = $("<div>");
var targets= $("#connected2, #connected3");
var ret = elem2[methodName]( targets );
console.log( ret === elem2 );
// → false  返り値が新しい jQuery オブジェクト

返った jQuery オブジェクトは常に 「指定した対象要素に加えられた要素」を保持します。 そのため、もし 対象として何の要素も 指定しなかった場合(例えば指定したセレクタで何の要素も マッチしなかった $(elements).appendTo("#not_found"))、 返った jQuery オブジェクトは何の要素も保持していません。

// 対象要素が無いとき
var elem3 = $("<div>");
var noneTarget = $("#not_found");
var ret = elem3[methodName]( noneTarget );
console.log( ret === elem3 );
// → false  返り値が新しい jQuery オブジェクト
console.log( ret.length );
// → 0      返された jQuery オブジェクトは要素を保持しない
リストに戻る

.trigger() された "click" イベント中の チェックボックスやラジオボタンの状態

ユーザがチェックボックスかラジオボタンをクリックすると、 そのイベントハンドラの中での クリックされたノードの状態は、 event.preventDefault()が呼ばれていたりしない限り、 クリック後の状態、つまり更新後の状態になります。

しかし 1.9 より前は、.trigger("click").click()で チェックボックスなどのクリックイベントをトリガーした場合、 そのイベントハンドラではトリガーされたノードの状態は クリック前の状態、更新前の状態になっていました。

1.9 では修正されて、ユーザがクリックしたときと同じ状態を 取得できるようになりました。

<-- 初期状態は未チェック -->
<input id="check" type="checkbox">
<input id="btn" type="button" value="clickCheckBox">
$(function(){
  $("#check").on("click", function(e){
    console.log("チェック:" + $(this).prop("checked") );
  });
  $("#btn").on("click", function(e){
    $("#check").click();
    // or $("#check").trigger("click")
  });
}
// 1.8 だと #btn を押して #check のクリックをトリガーした時
// checked プロパティが false で想定外の結果
// 1.9 だと true で想定と一致する
リストに戻る

.trigger() された "focus" イベントでの "blur" イベントとの発生順序

ユーザがフォームの要素にクリックやタブキーでフォーカスを 移動した場合、 ブラウザはそれまでフォーカスされていた要素の blur イベントを 発生させてから フォーカスした要素の focus イベントを 発生させます。しかし、 1.9 より前は、.trigger("focus").focus()を使った場合、 focus イベントが発生してから blur イベントが発生します。 そのため、1.9 でこの発生順序をユーザの操作の時と 同じ順序になるように変更されました。

ネイティブの DOM では、その要素がすでにフォーカスしていたり、 disabled になっている場合などでは、DOM の .focus()を実行しても focus イベントハンドラは実行されませんが、jQuery では そのような状況でも .trigger("focus").focus()で トリガーした場合は、jQuery で登録したイベントハンドラは 実行されます。この挙動は 1.9 でも同じだそうです。

IE (6-10)は focus イベントを非同期的に発生するため、 .trigger("focus")で イベントハンドラが2回実行してしまう恐れがあるそうです。 これを防止するには DOM の.focus()を使うように すればいいらしいのですが、その場合だと上で書いたように イベントハンドラが実行されない恐れがあるそうです。

リストに戻る

jQuery()に渡す HTML 文字列と セレクタ文字列の解釈方法

1.9 より前では、$()に渡した文字列に HTML タグが在るなら、その文字列は HTML 文字列とみなされていました。 そのため、valid なセレクタ文字列を指定しても 拒絶される可能性がありました。 1.9 からは、文字列の先頭に"<"がある場合のみ HTML 文字列とみなすようになりました。

"<"以外の文字で始まる文字列はセレクタと解釈されるので、 "<"で始まらない HTML 文字列を渡すとほぼ エラーになります。そのため、 "<"で始まらない HTML 文字列を使う場合は jQuery.parseHTML()に渡すようにしましょう。 このメソッドは HTML 文字列を DOM ノードの配列にして返すので、 例えば$( $.parseHTML( htmlString ) )とすれば HTML 文字列からjQuery オブジェクトが取得できます。

ただし、jQuery.parseHTML()を使えば安全、 というわけでも無いので、 安全なHTML 文字列だと確信できるときのみ 使うようにしましょう (参考: http://t-ashula.hateblo.jp/entry/2013/01/23/114105 )

jQuery Migrate plugin で判別方法を前のものに戻すことができます。

リストに戻る

ピリオドが含まれるキーを.data()に渡した時の処理

キーの中にピリオドが含まれていても、 ピリオドを含んだキーとして扱われるようになりました。 .data("abc.def")としても きちんとキー"abc.def"の値を取得します。

リストに戻る

HTML コンテンツ内でのスクリプトのロードと実行

1.9 より前は、$().append(), .wrap()などの HTML 文字列を受け取るメソッドは、 文字列中の script 要素が再び実行されてしまうことを防止するため、 ノードを作成するときにあらかじめ分離して DOM ツリーに挿入されないようにしておき、 スクリプトは別に実行するようにしていました。 それでもまだ.wrap()のようなメソッドで DOM ツリーの既存の script 要素を別の場所に移動してしまうと スクリプトが再実行されてしまいます。

1.9 からは、スクリプトはドキュメントに挿入されるように なりました(挿入時に実行されないように 無効化してから挿入し、スクリプトは別に実行しています)。 そして、script 要素が DOM ツリーに既に存在している場合は 要素に実行済みフラグを付けて、 script 要素を移動しても再実行されないようにしました。

また、script 要素を.clone()した時も、 クローンした script 要素には 実行済みフラグが付けられるようになりました。そのため、 既存の script 要素をクローンして挿入しても そのスクリプトは実行されません。 新しい script をロードするには、代わりに jQuery.getScript()を使うようにしましょう。

リストに戻る

.attr().prop()

jQuery 1.6.0 で.prop()を導入し、 ノードのプロパティの設定・取得に.attr()を 使用することは deprecated になりました。 しかし、後方互換性などの問題により 1.6.1 で Boolean 型のプロパティなどでは .attr() でも値が取得・設定 できるようになりました。 (このブログでも、 1.6.0 の時の記事 1.6.1 の時の記事 で、適当にまとめてあります。)

それで、この後方互換性を取るため .attr()の挙動を変えたため、 属性とプロパティのセレクタで少し不具合があったそうです。

例えば、セレクタ"input[checked]"の正しい挙動は、 その文字列値に関わらず、また 現在の状態に関わらず、 checked 属性を持つチェックボックスを選択することです。
それに対して、セレクタ"input:checked"は、 チェックボックスの真偽型(true or false)の checked プロパティ(これは例えばユーザがそのボックスを クリックしたときに影響される)を反映していて、 現在チェックされているチェックボックスを選択します。 1.9 より前のバージョンでは時々 これらのセレクタで正しい ノードを選択しなかったそうです。

以下は掲載されていた例です。これを見ると分かるように、 チェックボックスの現在の状態を反映し更新するのは プロパティです。属性を設定する必要はめったにありません。

$(elem).attr("checked", "checked");
  // 属性を変更したい場面なら正しい

$(elem).prop("checked", true);
  // チェックボックスをチェックする場合なら正しい

$(elem).removeAttr("checked");
  // 属性を削除したいのなら正しい

$(elem).prop("checked", false);
  // チェックボックスを 綺麗にする(チェックをはずす)場合なら正しい

もう一つの例として、input 要素の value プロパティ・属性があります。 属性は初期値で、プロパティは現在値です。 しかし、普通は.val()を使用して 取得・設定しているので、困る人はあまりいないでしょう。

しかし、例えば"input[value=abc]"のようなセレクタが 使われた場合、このセレクタは value 属性の値(HTML マークアップで指定された値)で選択されるべきで、 プロパティの値(例えば、ユーザが入力して変更した後の、 いわゆる現在値)で選択されるべきではありません。 1.9 未満のバージョンでは、このような属性を使用すべき場面で 時々プロパティを使用するそうで、これが 1.9 で 正しい挙動になったそうです。

jQuery Migrate plugin は 以前の 属性とプロパティのルールに 復元することができます。

リストに戻る

$("input").attr("type", newValue)

1.9 より前は、input や button 要素の type 属性を 設定しようとすると例外を throw していました。 これは input 要素の type を変更しようとするとエラーを throw する IE 6-8 に挙動を合わせていたためです。
1.9 からは、ブラウザによっては要素の type を設定することが できます。IE 6-8 では変わらずエラーを throw します。
jQuery Migrate plugin は ドキュメント内にあるそれらの要素の type 属性に設定しようとすると 警告はしますが、JavaScript エラーは throw しません。

リストに戻る

jQuery.ajaxの JSON データの取得成功判定方法

1.9 より前は、JSON や JSONP のデータを ajax で取得するとき 空文字列が返ると成功であるとみなされます。 success ハンドラには null が渡されます。
1.9 以降は、空文字列は不正な形式の JSON とみなされ エラーを throw します。
そのような場合を捕捉するには error ハンドラを使いましょう。

jQuery Migrate plugin はこのことを警告して、1.9 より前の 振る舞いに戻します。

リストに戻る

jQuery.proxy()のコンテキスト

1.9 では、jQuery.proxy()で コンテキスト(引数 context)に falseになるような値を指定した場合、 返される関数のコンテキスト(this)は そのまま引数で与えた関数のコンテキストを維持します。
要するに、そのjQuery.proxy()が実行された場所と 同じ場所で作成された、 普通の関数オブジェクトと同じコンテキストになります。

// 1.9
var fn = function(){ console.log( this ); }
var pFn = $.proxy(fn, false);

pFn(); // → Window (グローバルオブジェクト)
fn();  // → Window (グローバルオブジェクト)

var obj = { type: "anObj",  func1: pFn,  func2: fn };
obj.func1(); // → { type: "anObj", func1: function(), func2: function() }
obj.func2(); // → { type: "anObj", func1: function(), func2: function() }

var someObj = { type: "someObj" };
setTimeout(function(){
  pFn.call( someObj );
  fn.call( someObj );
}, 1000);
// → { type: "someObj" }
//    { type: "someObj" }

1.9 より前は、falseになるような値を コンテキスト(引数 context)に指定すると、 null, undefinedなら グローバルオブジェクト(window)に変換され、 他のfalseになる値はオブジェクトに ラップされていました(例 new Boolean(false))。

ただしどちらのバージョンも、空文字列をコンテキストに 設定しようとするとエラーになります(文字列だと jQuery.proxy()の別の用法とみなしてしまうため)。

リストに戻る

スポンサードリンク