電脳想

電脳想

デジタル社会の中で考え思うこと

Amebaでブログを始めよう!
この記事は、jQuery Advent Calendar 2014の10日目です。

今回は、jQuery関連で気づいた、ちょっとしたことをいくつか書き連ねてみます。

空のjQueryオブジェクト


意図的に$()なんて書くことはないと思いますが、セレクタで検索してみたら実はなかったとか、セレクタのスペルミスとかで、容易に空のjQueryオブジェクトが発生してしまいます。とはいえ、中身が空でもjQueryオブジェクトではあるので、メソッドは普通に呼び出せます。そして内部では、$.eachを使うなど、要素のlengthだけ回すようになっていますので、空であれば何も実行されないだけでエラーも起こさずに動きます。

一方、DOMを直接使った場合、例えばdocument.getElementById()で存在しないIDを指定した場合にはnullを返しますので、メソッドを呼ぼうとすればエラーになります。

jQuery関数の引数


jQuery()、あるいは略して$()の引数としては、いろいろなものを与えられます(公式ドキュメント)。

null、undefined(省略した場合も含む)、空文字列、false、0、NaN

空のjQueryオブジェクトを作成します。

文字列

先頭が<ならHTMLとしてパースしたものをjQueryオブジェクトに変換し、それ以外ならセレクタとして検索した結果をjQueryオブジェクトとします。

DOMオブジェクト、またはその配列

引数をjQueryオブジェクトに変換します。

jQueryオブジェクト

同じ要素を指すjQueryオブジェクトを作成します。

関数

その関数をreadyイベントに登録します。なお、返り値は$(document)なので、(実用性はともかく)さらにメソッドチェーンにすることもできます。

その他の引数

jQueryで引数をラップします。dataやイベント系の関数を使えるようですが、使い道がピンときません。


class属性を操作


jQueryには、クラス操作のためにaddClassremoveClasstoggleなどの関数が備わっていますが、状況によってはこれらの関数を使わずに、直接class属性を変更するように動かすこともできます。

例えば、「ある要素を、以前の状態にかかわらず特定のクラスにしたい」ということであれば、$(要素).attr('class','指定したいクラス')とできますし、クラスを全て削除したいのであればremoveAttrを使えます(実は、removeClassを引数なしで呼ぶと全クラスが削除されるのですが)。

これが本当のメソッドチェーン


JavaScriptでは、foo.barfoo['bar']は同じものです。これを利用すれば、よりチェーンに見えるようなメソッドチェーンを行うことができます。もっとも、(動的にメソッドを切り替えられる点を除けば)そう役には立たないと思いますが。

//普通の書き方
$("#foo").attr('bar','baz').addClass('hoge').appendTo('body');
//よりチェーンっぽく
$("#foo")['attr']('bar','baz')['addClass']('hoge')['appendTo']('body');
この記事は、携帯電話Advent Calendarの6日目です。

最近はスマートフォンに乗り換える人だけではなくて、スマートフォンとガラケーの2台持ち、という人もいますが、自分の場合は「ガラケー2台」を持ち歩いています。しかも、昔はスマートフォンを使っていたというややこしさです。

最初に契約したのがドコモで、そしてまだスマホが市民権を得ていなかった頃にウィルコムのアドエスを契約して2台持ちとなりました。さらに、一時はイオンSIMでIDEOSを契約し、ガラケー+スマホ+スマホの3台持ちとなっていたこともありました。

転機となったのは、音楽用に使っていたiPodをiPod Touchに買い換えたことでした。いっときは新つなぎ放題980円という叩き売り契約でアドエスを格安で使い、余ったW-SIMはnineに挿して使っていたのですが、しだいにiPod利用がメインとなり、ウィルコムの契約は誰とでも定額に転換し、新つなぎ放題はタイミングを見て解約となりました。そして、データ専用端末の契約(WiMAXからぷらら3M に乗り換え)、IDEOSの紛失→解約、nineがヘタってきたので機種変更を行い、現在に至ります。

最近は「SIMフリー」なんて言いますが、iPod Touchで無線LANに変換できれば「回線フリー」という使い方も、悪くないなと思う今日このごろです。

明日はmikzoさんです。よろしくお願いいたします。
この記事は、jQuery Advent Calendar 2014の4日目です。

jQueryネタで何か書こうとして下調べしていたら、意外なことに気づいたのでそれを記事化することにしました。



ノードのキャッシュ


JavaScriptで大量の要素を組み立てる場合、都度HTMLをパースしたり、エレメントを生成したりといったコストを避けるために、あらかじめ1つだけエレメントを用意しておいて、それをcloneNode()することで賄う、というような手法が定石となっていて、jQueryでもclone()メソッドがあります。

コピーしないほうが…速い!?


ところが、jsPerfで測定していたところ、奇妙な現象が起きました。なんと、clone()せずに、都度HTMLからjQueryオブジェクトを生成するほうが速くなってしまったのです。

jQueryのソースコードを追ってみると、HTMLからDOMを生成する$.parseHTML()で、<foo /><foo></foo>のような空タグの場合は正規表現で振り分けて、document.createElement()に投げるようになっており、これでHTMLのパースをバイパスしているので速かったのでした。もちろん、そんなものもすべてかっ飛ばして、自力でdocument.createElement()したものをjQueryに変換すればもっと高速になります。jQueryを使っていても、生DOMの知識があれば、さらに使いこなすことができます。

clone()の遅さの要因


そこで、今度はclone()だけの速度を測定してみました。今回は、1エレメントだけのものと、いくつかのエレメントが入ったものについて、

  1. jQueryの.clone()を使用

  2. DOMのcloneNode()を使った上で、jQueryに変換

  3. (参考)DOMのcloneNode()だけの速度


を比較してみました。2番目と3番目の差はjQueryオブジェクト生成のコスト、そして1番目と2番目の差は.clone()のオーバーヘッド、ということになります。

測定結果からわかるように、.clone()は単純にcloneNode()したものをjQueryに変換した場合と比べて、10倍以上の時間を要しています。ソースから読み取れることとしては、

  • jQueryオブジェクトが複数エレメントでもちゃんとcloneできるように処理を開く

  • 古いIEなどで、フォーム要素の状態や、HTML5で追加になったタグがうまくコピーされない問題の解消

  • scriptタグを検索しての特別処理

  • jQuery内部で持っている、イベントやデータのコピー


などの処理が加わっています。とはいえ、テンプレートをコピーするような場面では、scriptタグはまず現れないでしょうし、動的に生成する要素で全てにイベントを割り当てるのであれば、そうするより.on()で拾うべき場面でしょう。このような問題がない、親要素1つの中に全て入ったようなテンプレートであれば、jQueryの.clone()を使うよりネイティブにcloneNode()してからjQueryオブジェクトにしたほうが格段に速いことを、知っておいて損はないと思います(もちろん、100個もコピーしないのであれば、速度向上と言っても微々たるもので、そこまでの意味は持たないでしょうが)。