jQuery の data() 等のダッシュ(-)を含むキーの取り扱いの違い

jQuery.data()jQuery.fn.data()を 使うと要素(やオブジェクト)ごとに Key-Value の形でデータを 保存することが出来ます。 また、jQuery.fn.data()では HTML 属性 data-* の値を取得することができます。 この属性 data-* まわりの処理のためか、 キーにダッシュ(-)が含まれている場合、 処理に一貫性が無くなり、1.x 系と 2.x 系で振る舞いが 異なる箇所も出てきます。

そのようなわけで、キーにダッシュが含まれている場合に どのような振る舞いになるのかを調べてみましたが、 キーにダッシュを含めなければいい話なので、 元々キーにダッシュを含めていない人は もうこれ以降読む必要が無いかもしれません。

主に jQuery 2.1.0 と 1.11.0 (あとおざなりに 2.0.3, 1.10.2, 1.9.1) を使って調べたので、他のバージョンでは 当てはまらないことがあるかもしれませんのでご注意下さい。

jQuery.fn.data()での扱い

jQuery.fn.data( key, value )の場合

key に文字列でダッシュ付きキーを、value に値を指定した場合、 基本的にはキーはキャメルケースに変換されて登録されます。 しかし 2.x 系では、 最初(そのキャメル化キーでデータが未登録の場合)は キャメル化キーのみで登録されますが、 2回目(そのキャメル化キーでデータが登録済みの場合)は キャメル化キーだけでなくダッシュ付きキーでも登録されます。

// ※ダッシュ付きをスネークケースと勘違いしていますが無視して下さい
var elem = document.createElement("div");
// fn.data() の場合
// 基本、キーはキャメル化されて登録されるが、、、
// 最初(正確にはそのキーでデータ登録されてない場合)は
// キャメル化キーのみ
$( elem ).data("snake-case", 30);
console.log( $( elem ).data() );
// → Object { snakeCase=30}

// 2回目以降はダッシュ付きキーも共に登録される(2.x系)
$( elem ).data("snake-case", 50);
console.log( $( elem ).data() );
// →Object { snakeCase=50, snake-case=50}
リストに戻る

jQuery.fn.data( obj )の場合

オブジェクトを指定するとプロパティ名がキーとして、 プロパティの値がそのキーの値として登録されます。 オブジェクトを指定してダッシュ付きキーを指定した場合は、 キャメル化されずにそのままのキーで登録されます。

// ※上の続き
// オブジェクトを指定して登録する場合はキャメル化されない
$( elem ).data({ "snake-case": 75});
console.log( $( elem ).data() );
// →Object { snakeCase=50, snake-case=75}
リストに戻る

jQuery.fn.data( key )の場合

キーだけを指定するとそのキーの値が読み出されますが、 ダッシュ付きキーだけを指定した場合、まずダッシュ付きキー そのままで値が登録されているか調べ、登録されていなければ 次にキャメル化キーを試し、それも無ければ HTML の data-* 属性を調べます。

// ※上の続きではない
var elem = document.createElement("div");

// fn.data( key ) の読み出しは
// 生キー → キャメル化キー → data-* 属性 の順

$( elem ).attr("data-snake-case", 50);
console.log( $( elem ).data("snake-case") );
// →50
// ※この時点で data には キー"snakeCase"・値50 のデータが入る
$( elem ).data("snakeCase", 100);
console.log( $( elem ).data("snake-case") );
// →100
$( elem ).data({ "snake-case": 150 });
console.log( $( elem ).data("snake-case") );
// →150
リストに戻る

jQuery.data()での取り扱い

jQuery.data( elem, key, value )の場合

key に文字列でダッシュ付きキーを、value で値を指定した場合、 2.x 系ではダッシュ付きキーそのままで登録されますが、 1.x 系ではキャメル化キーで登録されます。

// ※elem は DOM 要素
// jQuery.data( elem, key, value ) は
// 2.x 系では生キー、1.x 系ではキャメル化キーで登録
jQuery.data( elem, "snake-case1", 50);
jQuery.data( elem, "snake-case2", 100);
console.log( jQuery.data( elem ) );
// 1.x 系
// →Object { snakeCase1=50, snakeCase2=100}
// 2.x 系
// →Object { snake-case1=50, snake-case2=100}
リストに戻る

jQuery.data( elem, obj )の場合

ダッシュ付きキーをオブジェクトで指定した場合は jQuery.fn.data()と同じく キャメル化されずにそのままのキーで登録されます。

// ※elem は DOM 要素
// jQuery.data( elem, obj ) は
// そのままのキーで登録
jQuery.data( elem, { "snake-case1": 30,
                     "snake-case2": 60 });
console.log( jQuery.data( elem ) );
// →Object { snake-case1=30, snake-case2=60}
リストに戻る

jQuery.data( elem, key )の場合

ダッシュ付きキーだけを指定した場合、まずダッシュ付きキー そのままで値が登録されているか調べ、登録されていなければ 次にキャメル化キーを試します。 jQuery.fn.data()と違って HTML の data-* 属性は調べません。

// ※上の続きではない
var elem = document.createElement("div");

// jQuery.data( elem, key ) の読み出しは
// 生キー → キャメル化キー の順

$( elem ).attr("data-snake-case", 50);
console.log( jQuery.data( elem, "snake-case") );
// →undefined
jQuery.data( elem, { "snakeCase": 100 });
console.log( jQuery.data( elem, "snake-case") );
// →100
jQuery.data( elem, { "snake-case": 150 });
console.log( jQuery.data( elem, "snake-case") );
// →150
リストに戻る

jQuery.fn.removeData(), jQuery.removeData()での取り扱い

jQuery.fn.removeData(), jQuery.removeData()は指定したキーを削除します。 キーの指定方法には単数指定(文字列)と 複数指定(配列、空白で区切った文字列)があります。 キーを指定しないと全削除になります。

一つのキーを削除する場合(.removeData(key))

キーを文字列値で指定するとそのキーが削除されます。 2.x 系ではそのままのキーとキャメル化キーの両方が 削除されますので、ダッシュ付きキーを指定した場合は ダッシュ付きキーとキャメル化キーの両方が削除されます。 1.x 系ではそのままのキーが存在したらそのキーを削除して その時点で終了し、無ければキャメル化キーの存在を調べて 削除します。 つまり 1.x 系ではダッシュ付きキーとキャメル化キーの両方が 存在した場合、ダッシュ付きキーを指定しても キャメル化キーが削除されません。

// ※jQuery.fn.removeData と jQuery.removeData は
//   ダッシュ付きキーの処理に関しては同じ

var elem = document.createElement("div");

// キー一つを指定した場合、
// 1.x 系では キーそのまま→キャメル化されたキー の順に
// 調べて見つかった時点でそのキーを削除して終了する
// 2.x 系では キーそのまま と キャメル化されたキーを
// 両方削除する
$( elem ).data({ "snake-case1": 25,
                 "snake-case2": 50,
                 "snakeCase1": 75,
                 "snakeCase2": 100  });
console.log( $( elem ).data() );
// →Object { snake-case1=25, snake-case2=50,
//            snakeCase1=75, snakeCase2=100  }
$( elem ).removeData("snake-case1");
console.log( $( elem ).data() );
// 2.x 系
// →Object { snake-case2=50, snakeCase2=100}
// 1.x 系
// →Object { snake-case2=50, snakeCase1=75, snakeCase2=100}
$( elem ).removeData("snakeCase2");
console.log( $( elem ).data() );
// 2.x 系
// →Object { snake-case2=50}
// 1.x 系
// →Object { snake-case2=50, snakeCase1=75}
リストに戻る

複数のキーを削除する場合 (.removeData([key1, key2, ...]), .removeData("key1 key2 ..."))

複数キーの指定方法は2種類あります。 一つはキー(文字列)の配列を指定する方法で、 この指定方法ではそのままのキーとキャメル化キーの両方が 削除されます。 もう一つは空白で区切った文字列で指定する方法で、 この指定方法ではキャメル化キーのみが削除されます。 つまり文字列指定では、 ダッシュ付きキーとキャメル化キーの両方が存在した場合に ダッシュ付きキーを指定してもキャメル化キーしか削除されません。

// ※elem は DOM 要素

// 配列指定の場合はキャメル化されたキーも削除される
$( elem ).data({ "snake-case1": 25,
                 "snake-case2": 50,
                 "snakeCase1": 75,
                 "snakeCase2": 100  });
console.log( $( elem ).data() );
// →Object { snake-case1=25, snake-case2=50,
//            snakeCase1=75, snakeCase2=100  }
$( elem ).removeData(["snake-case1", "snake-case2"]);
console.log( $( elem ).data() );
// →Object {}

// 空白で区切った文字列での指定の場合はキャメル化された
// キー「のみ」削除される
$( elem ).data({ "snake-case1": 25,
                 "snake-case2": 50,
                 "snakeCase1": 75,
                 "snakeCase2": 100  });
console.log( $( elem ).data() );
// →Object { snake-case1=25, snake-case2=50,
//            snakeCase1=75, snakeCase2=100  }
$( elem ).removeData("snake-case1 snake-case2");
console.log( $( elem ).data() );
// →Object { snake-case1=25, snake-case2=50}
リストに戻る

まとめ

ダッシュ付きのキーを使わないようにしましょう。 使う場合でも、 jQuery.fn.data()jQuery.data()を 混ぜこぜで使ったり、 複数のキーを操作する便利な用法を使ったりしなければ 大丈夫だと思います。

  • jQuery.fn.data()
    • キー登録(data(key, value))
      • 2.x 系

        最初(キャメル化キーに未登録)はキャメル化キーのみ

        2回目(キャメル化キーに登録済)は生キーも共に

      • 1.x 系

        キャメル化キーのみ

    • キー登録(data(object))

      生キー

    • キー読み出し(data(key))

      生キー → キャメル化キー → data- 属性 の順

  • jQuery.data()
    • キー登録(data(key, value))
      • 2.x 系

        生キー

      • 1.x 系

        キャメル化キー

    • キー登録(data(object))

      生キー

    • キー読み出し(data(key))

      生キー → キャメル化キー の順

  • jQuery.fn.removeData(), jQuery.removeData()
    • 単数キー(.removeData(key))
      • 2.x 系

        生キー・キャメル化キー 両方

      • 1.x 系

        生キー → キャメル化キー の順に調べ 初見のキーを削除した時点で終了する

    • 複数キー
      • 配列指定(.removeData([key1,key2, ...]))

        生キー・キャメル化キー 両方

      • 文字列指定(.removeData("key1 key2 ..."))

        キャメル化キーのみ

リストに戻る

おまけ:データを空にしたときの注意点

1.x 系では jQuery.fn.removeData()jQuery.removeData()を使ってデータを空にした時、 データオブジェクトが変更されます。 2.x 系でも上の2つのメソッドを引数無しで実行してデータを 空にした時はデータオブジェクトが交換されます。

// ※elem は DOM 要素
// 全削除で空にした場合
$( elem ).data({ "snake-case1": 25,
                 "snake-case2": 50 });
var data1 = $( elem ).data();
console.log( data1 );
// →Object { snake-case1=25, snake-case2=50}
$( elem ).removeData(); // 全削除で空にする
var data2 = $( elem ).data();
console.log( data1 );
// →Object { snake-case1=25, snake-case2=50}
//   ※全削除だとデータオブジェクトが交換される
console.log( data2 );
// →Object { }

// キー指定で空にした場合
$( elem ).data({ "snake-case1": 30 });
var data3 = $( elem ).data();
console.log( data3 );
// →Object { snake-case1=30}
$( elem ).removeData(["snake-case1"]); // キー指定で空にする
var data4 = $( elem ).data();
console.log( data3 );
// →Object { }
console.log( data4 )
// →Object { }
console.log( data3 === data4 );
// 2.x 系
// →true
// 1.x 系
// →false
//   ※1.x 系だと削除後、データオブジェクトが空の場合
//     キャッシュからデータオブジェクトも削除されるため、
//     その後の操作で再生成されるデータオブジェクトは
//     以前のデータオブジェクトと異なる
リストに戻る

スポンサードリンク