jQuery使って闇を生み出すのはいやだけどjQueryでやったほうが幸せになることだってあるんじゃよ……
今回はjQueryのattrとporpの使い分けの話です。
本題:ここ
jQueryあるあるのattrとprop問題
WebをやるのにjQueryは2016年の終わろうとしている今でも世界中で重宝されています。罪ですね。
最近はjQueryでは手に負えなくなって、あるいはjQueryの「コレジャナイ」間に気付いて……まあ様々な理由の上でReactやVue.jsのようなFWが使われるようなことが多くなってきましたが、jQueryは適材適所で使われ続けています。FWと併用されることもあります。闇ですね。
※ 新しく使う場合は3.x系を使いましょう……
そんなjQueryですが、1.6よりそれまでのattrはattrとpropに分離されました。(5年半前)
で、これは当時も混乱する人が多かったようですが、今でも後を絶たないことが明白です。(私調べ)
間違えるとattr警察の方々に殺されます、というより動きません。
では、どうやって覚えればいいのでしょうか。
まあ具体例示せよ
dataの扱いは特殊なので基本的にattr使うようにしてるんですが……基本的にはこのQiita記事の言うとおりです。
jqueryのattrとprop(とdataとvalとhtmlとかつまり属性とかの取得)の使い分け一覧 – Qiita
で、肝心のattrとpropのおぼえかた
attrは名前の通りHTML(DOM)の属性、propはプロパティです。
つまり、生DOMを想定してelement.hogeでアクセスできるプロパティはpropを、それ以外の属性(生DOMのAPIではelement.attributes.hoge.value (readonly)だとか element.getAttribute('type')/element.setAttribute('name', 'value') のような形でアクセスする必要のある)についてはattrを使えばいいんです。
生DOMがわからないからjQuery使ってるんだよなんて言わないでください、jQueryはあくまでもDOMを扱いやすくするためのライブラリでしか無いんだから……
といっても分かりにくいかもしれないので1つサンプルを用意しました。
さて、このPenをRunし、「input」の上で右クリック⇒検証(Chromeの場合)でこのinputにフォーカスが当たっている状態のインスペクタを開きましょう。
こんな感じになってるはずです。
ちなみに、ChromeやSafariではこの状態でコンソールを開けば$0で当該要素にアクセスできます。
たとえば、$0.valueとすれば、"input"が返ってきます。
また、$0.getAttribute('value')でも同様の値が得られています。
では、プレビュー画面よりこのinputの値を適当な文字に変えてみましょう。
ここで、もう一度DOMツリーを見てみましょう。
このinputはDOMツリー上では<input value="input">のままになっています。
では、コンソール上でプロパティをみると……
反映が確認できます。jQueryの$formElement.val()はこの値ですね。
同様に属性を見てみると……
inputのままです。属性はプロパティではないので状態保存はしていません。
同様に、下にあるチェックボックスをインスペクタでフォーカスしましょう。
ただの<input type="checkbox">です。
チェックボックスのチェック状態を保持するプロパティはcheckbox.checkedですね。
$0.checkedはこの場合falseが返ってくるはずです。
また、checked属性は付けていないので$0.getAttribute('checked')はnullを返します。
先程同様、こちらもチェックボックスをクリックしチェックします。
DOMツリー上では何も変化はないように見えますが、$0.checkedはtrueを返すようになります。
なお、属性はnullのままです。
checkboxで$el.attr(‘checked’)をすると死ぬというのはまさにこれですね。
チェックボックスやinputにおける属性は初期値でしか無いのです。既に存在するフォームのvalueはこれでは変わりません。
textareaの要素内の文字列も同様です。
もちろん、jQueryの:checkedセレクタはこのプロパティを利用していました。(最近はdocument.querySelectorの方使ってたっけ?)
では、DOMに変化がない場合のみがプロパティの使うべきか、とうと残念ながらそういうわけではありません。
再びinputの方にインスペクタのフォーカスを当て、その横の[toggle]をクリックしてみましょう。inputが無効化されます。
この無効化というのはinputのプロパティである$0.disabledで切り替えているわけなのですが、この操作を行うと当該の要素にdisabled属性が現れます。なんということでしょう。
いきなり言ってることが真逆で意味がわからないかもしれませんが、これは属性を直接切り替えても操作することが可能です。
とはいえ、DOMの操作にはプロパティを使うようにしましょう。
基本的にbooleanや数値など文字列型以外が現れるならばそれはプロパティです。もちろん、element.className のように属性に直接影響するプロパティも多々存在しますが、data-*のようなHTML(DOM)を媒介したデータのやり取りにはattr,属性を利用することになります。(今時殆どのブラウザがdataset対応してるんだからそれでいいじゃないのみたいなのも……ウッ)
おまけ: a要素のhrefを取得する
DOMにおけるA要素は面白い存在で、 HTMLHyperlinkElementUtilsを継承しているためhrefのURLを詳細に操作することが出来ます。(他にarea要素も同様)
具体的にはURLと同様の似たインタフェースが実装されています。
具体的には、リンク先のURLについてhrefにセットしたURL以外にも、<base>を計算した上でのoriginやhostname、port(URIに明示的に含まれている場合のみ)、pathname等がa要素のプロパティとして取得できます。
もちろん、これらのプロパティはjQueryのpropで取得が可能です。
たとえば、以下のpenはa要素の持つ全てのプロパティを表示させたものです。(関係ないのも全て表示してるので最悪)
なお、このhrefプロパティも計算済みのフルの値になるため、実際にHTMLにあるURLを取得したければ属性、つまりattrで取得が必要なわけですね。(メニューのactiveページ判定にこれを使っているコードがあるのを見かけました……)
もちろん入力値以外で相対URLを吐き出す機能なんてものは用意されていないので自力で実装するかなんかしてやる必要がありますが、常識的に考えてそんなシチュはシチュはまずないかと思います。有って堪るか
まとめ
attrとpropの使い分けの見抜き方の話でした。ほとんど脱線した……
結論としてはattrはdata-*以外殆ど使わない、propが使えるならばそっち。
そもそもpropよりもvalやaddClassのようなメソッドが用意されているならばそっちを使おう、ということです。





