JavaScript でオブジェクトのメンバであるメソッドをイベントハンドラにしたときに非 DOM の this を取りたい

ちょっとエントリのタイトルが微妙だが、まず次の HTML + JavaScript コードをご覧いただきたい。(前後の HTML コードをカットしている) s1 ボタン 上記を実行して「s1 ボタン」をクリックすると、「This is s1ButtonName」とアラートが表示される。 これはイベントでは this がイベント送出の DOM オブジェクトとなるからだ。button 要素の name 属性が this.name となる。s1.button_click を呼び出していても、this.name が “s1” とはならない。 こういうコーディングをしたい場合、今まで SampleA に当たるものがシングルトンだった。そのため、this の代わりに SampleA.name とベタに定義してしまっても問題がなかった。 ということで、複数インスタンスを作りたい場合どうすれば良いかというのが本題である。 あるオブジェクトのメソッドの中でイベントを無名関数で定義するならば、その中でその外のスコープの this を参照 したいときは with やローカル変数に一旦代入することで拾えるようになる。 例えば、このようなな感じで書くだろう。 var sample = { name: “名前”, display: function(){ var that = this; $(“s1button”).click(function(){ alert(that.name); }); } }; ...

2009年1月10日 · Toshimitsu Takahashi

jQuery の Manipulation(DOM 操作)で優先的に使うべきメソッドのまとめ

jQuery 1.2.6 のソースコードを見ると、appendTo, prependTo, insertBefore, insertAfter, replaceAll の定義は下記のように、内部で append, prepend, before, after, replaceWith を呼び出し元、引数の対象を逆にして呼び出すようになっていることがわかる。 jQuery.each({ appendTo: “append”, prependTo: “prepend”, insertBefore: “before”, insertAfter: “after”, replaceAll: “replaceWith” }, function(name, original){ jQuery.fn[ name ] = function() { var args = arguments; return this.each(function(){ for ( var i = 0, length = args.length; i < length; i++ ) jQuery( args[ i ] )[ original ]( this ); }); }; }); あくまでも append, prepend, before, after, replaceWith がオリジナルのメソッドなのだ。 処理のステップを少なくするには、appendTo, prependTo, insertBefore, insertAfter, replaceAll はメソッドチェーン的に書きやすいか、引数となる対象が jQuery オブジェクトではない場合に限った方がよいだろう。 A.appendTo(B) とも B.append(A) とも変数 A, B がどちらも jQuery オブジェクトであるなら、後者を選んだ方がよい。 DOM 操作をするときは(replaceWith は除くが)append, prepend, before, after とメソッド名が短い方を選ぶと覚えておこう。

2008年12月25日 · Toshimitsu Takahashi

jQuery の ID で対象ノードを取得する処理を高速にしたい

てっく煮ブログさんのエントリー jQuery を高速に使う CSS セレクタの書き方 - てっく煮ブログ をみてて、jQuery の $("#xxxx") を速くしたいと考えていたことを思いだした。それについて書く。 jQuery の $("#xxxx") について セレクタをどう処理しているのか jquery-1.2.6.js で確認してみよう。 まず下記の init が $() に相当する。Handle HTML stringsのところで引数が string だと quickExpr.exec が走る。これは正規表現でのセレクタ解析処理である。 その後、HANDLE: $("#id")のところでマッチして取得した ID を使って、var elem = document.getElementById 使い、それを return jQuery(elem) として再び init が呼び出される。 jQuery.fn = jQuery.prototype = { init: function( selector, context ) { // Make sure that a selection was provided selector = selector || document; // Handle $(DOMElement) if ( selector.nodeType ) { this[0] = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector == “string” ) { // Are we dealing with HTML string or an ID? var match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) selector = jQuery.clean( [ match[1] ], context ); // HANDLE: $("#id") else { var elem = document.getElementById( match[3] ); // Make sure an element was located if ( elem ){ // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id != match[3] ) return jQuery().find( selector ); // Otherwise, we inject the element directly into the jQuery object return jQuery( elem ); } selector = []; } // HANDLE: $(expr, [context]) // (which is just equivalent to: $(content).find(expr) } else return jQuery( context ).find( selector ); // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) return jQuery( document )[ jQuery.fn.ready ? “ready” : “load” ]( selector ); return this.setArray(jQuery.makeArray(selector)); }, ...

2008年12月11日 · Toshimitsu Takahashi

jQuery の $(selector, context) な書き方は context.find(selector) を使うべきだった件について

先日、404 Not Found に参加しました。 #1 は未参加だったので、 jQuery.fn.init() について後から読んでいたのですが、あまり Travesing API を見ていなかったので、あるノード以下から選択するときは、 $(".classname", context) みたいに書いてました。 jquery-1.2.6.js / Line 73 - 76 // HANDLE: $(expr, \[context\]) // (which is just equivalent to: $(content).find(expr) } else return jQuery( context ).find( selector ); とあるとおり完全にオーバーヘッドでした。 上記の抜粋部分に辿りつくには、正義表現で expr を解析するステップ(下記の部分)が発生していて、find 呼び出しのブロックに流れるとその結果を捨てています。この解析では expr が生成用の HTML 文字列もしくは ID セレクトかを判別しているからです。どちらでもない場合は、find となります。よって $("#id", context) というセレクタが ID 指定の場合には今回の話は当てはまりません。 jquery-1.2.6.js / Line 47 - 50 // Are we dealing with HTML string or an ID? var match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match\[1\] || !context) ) { 最初に『あるエレメント下のものを対象にしたい』と調べていたら、まず jQuery( expression, [context] )に辿りついたので、何も考えずにこの書き方をしてました。これからは context.find(selector) を使うようにします。 ...

2008年6月19日 · Toshimitsu Takahashi

jQuery UI の Dialog を使って確認用モーダルダイアログを実装するには

jQuery UI (http://ui.jquery.com/) には便利なコンポーネントがある。このダイアログを使ってユーザーへの確認に使うモーダルダイアログを作りたい。 設定仕様に幅がある分、わかりずらいところがある。ということで下記のように手軽に使える用に関数を作ってみた。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /* * 確認ダイアログ * * message : ダイアログのメッセージ本文 * title : ダイアログのタイトル * buttonok : OKボタンのテキスト * buttoncancel : キャンセルボタンのテキスト * response : コールバック関数を指定する。引数 cancel にボタン選択の結果が入る。 * OK ならば false キャンセルならば true となる。 */ function confirmDialog(message, title, buttonok, buttoncancel, response){ var _dlg = $('<div>'+message+'</div>'); var _buttons = {}; _buttons[buttonok] = function(){$(this).dialog('close');response(false)}; _buttons[buttoncancel] = function(){$(this).dialog('close');response(true)}; _dlg.dialog({ modal:true, draggable:false, title:title, height:130, width:320, buttons:_buttons, overlay:{ opacity:0.3, background:'#225B7F' } }); } /* Sample */ confirmDialog('この処理を続行しますか?', '確認', 'OK', 'キャンセル', function(cancel){ if (cancel) return; /*------------ 処理を書く ------------*/ }); ダイアログのベースとなる div は Document DOM ツリーに存在していなくてもいいので生成して、dialog() を呼び出すだけで動く。これは便利だ。dialog の引数で様々な設定が可能である。上記の例では見た目を一つのアプリで統一するので幅、高さなど固定で定義している。あとは modal 化と背景がクリックできないことを明示するために overlay を設定している。 ちょっとわかりづらいのは、buttons で表示ボタンがという設定できるのだが、ボタンのラベル値がキーであり、対となる値が選択時に走る関数の定義となるところだ。定義の例では、ボタン名としてキーを変数値にしたいために map[key] = func としてセットしている。

2008年6月16日 · Toshimitsu Takahashi

jQuery の hover() について調べたことのまとめ

hover() は mouseenter と mouseleave を同時にセットする http://docs.jquery.com/Events/hover の引数の名前付けを見て、hover は mouseover と mouseout を同時に指定するものだと思っていたが違うらしい。 jquery-1.2.6.js の 2278 行付近 hover: function(fnOver, fnOut) { return this.bind(‘mouseenter’, fnOver).bind(‘mouseleave’, fnOut); }, とあるように mouseenter と mouseleave に対して指定するものである。 over/outと enter/leave の違いは、http://docs.jquery.com/Events/mouseover の Demo みるとよくわかる。 ある領域 A にカーソルが載ったときに、領域 A 内に動的にブロック B を表示するという処理を次のようなに作っていた。 http://tilfin.googlepages.com/overout.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-script-type" content="text/javascript"> <script src="jquery-1.2.6.js"></script> <title>jquery mouseover / mouseout</title> <style type="text/css"><!-- #A { color:#fff; background-color:blue; border:1px solid #000; width:300px; height:200px; position:relative; } #B { color:#fff; background-color:red; border:1px solid #000; display:none; width:200px; height:100px; position:absolute; bottom:0; right:0; } #debug p { margin:0; line-height:110%; font-size:9pt; } //--></style> <script><!-- $(document).ready(function(){ $("#A") .mouseover(function(){ $("#debug").append("<p>A: mouseover</p>"); $("#B").appendTo(this).show(); }) .mouseout(function(){ $("#debug").append("<p>A: mouseout</p>"); $("#B").hide().appendTo(document.body); }); }); //--></script> </head> <body> <div id="A">A</div> <div id="B">B</div> <div id="debug"></div> </body> </html> しかし、これだと表示されたブロック B にカーソルが載ったとき、A の mouseout が発生するためちらつきが起こってしまう(これは Firefox のときで IE ではちらつきではなく消えたままになった)。 ...

2008年6月15日 · Toshimitsu Takahashi

Ajax アプリケーションのステータス変更をタイトルをロールさせて目立たせたい

おそらく常に起動している(開いている)ような Ajax アプリケーションを使う場合、タブブラウザを使っていることがほとんどだろう。そのアプリが例えば『新着メッセージがある』といった状態が変わったことを通知したいときに、ユーザーに目立たせるにはどうしたらよいだろうか。 Gears などを使うとブラウザ外へのアラートができるようだが、普通に行うにはタブ(タイトル)部分に注目させることになるだろう。そこでタイトルをロールしてみるサンプルを書いてみた。 TitleRoll クラス function TitleRoll(){} TitleRoll.prototype = { timerid: null, start: function(text, interval){ var itv = (interval != undefined) ? interval : 500; this.text = document.title; document.title = text + " “; this.timerid = setInterval(function(){ with(document){ title = title.substr(1) + title.substr(0, 1); } }, itv); }, stop: function(){ if (this.timerid == null) return; clearInterval(this.timerid); this.timerid = null; document.title = this.text; }, isrolling: function(){ return (this.timerid != null); } }; ...

2008年6月7日 · Toshimitsu Takahashi

JavaScript の JIT 導入やバイトコード化

JavaScript 高速化へ Safari3より4倍高速、WebKit新JavaScriptエンジン"SquirrelFish" | マイナビニュース Adobe高速JavaScript実装、バイトコードにForthを採用 | マイナビニュース

2008年6月5日 · Toshimitsu Takahashi

Google AJAX Libraries API の使い方まとめ

Google Hosted Libraries - Developer’s Guide - Make the Web Faster — Google Developers Google が下記の主要 JavaScript ライブラリのホスティングを開始したので、以前作ったガジェットのソースを変更することにした。 jQuery prototype script_aculo_us MooTools dojo 『Google AJAX Libraries API』とホスティングだけで API って大げさな気がしたが、インターフェイスが確かにあった。また、script タグでの src 指定でもよい。 Google.load Google AJAX API を既に使っているのであれば Google.load 関数のライブラリ名とバージョンを指定してロードできる。Maps, Feed などと合わせて使うならこっちが便利だろう。 は、jQuery の 1.2.* な最新バージョンをロードして使用する。現在の最新は 1.2.6 だがより新しいバージョンがリリースされ Google がホストすれば自動的に新しいものを使うようになる。もちろんフルでバージョンを 1.2.3 のように指定すればそれを永続的に使える。欠点は動的ロードになるので document のロード終了時までライブラリの機能を使用できない。 script タグでの指定 単に url パスでも指定できるのでそれを使ってもよい。ドキュメントには載っていなかったがこちらも実はワイルドカード的なバージョン指定も可能なようだ。 下記からは全て jQuery Ver.1.2.6 がロードできる。 http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js http://ajax.googleapis.com/ajax/libs/jquery/1.2/jquery.min.js http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js こっちの方がすぐ使えて便利だと思う。 ...

2008年6月4日 · Toshimitsu Takahashi

XMLHttpRequest でのステータスコード 304 (Not Modified) について

IE の Ajax (XMLHTTP) で、通信が行われたかキャッシュが使われたかを判定する方法 - IT戦記 を読んで、レスポンスのステータスコード見るのが本来のやり方なのではと思い、試してみたら意外な結果になった。 テスト content.txt を採りに行って表示するだけの下記のサンプルをそれぞれブラウザで表示して、リンクをクリックしたときレスポンスコードがどうなるか試してみた。 Internet Explorer 用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <html> <head> <script type="text/javascript"> function test(){ var req = new ActiveXObject('Microsoft.XMLHTTP'); req.onreadystatechange = function(){ if (req.readyState == 4) { alert(req.status); } }; req.open('GET', 'content.txt'); req.send(); } </script> </head> <body> <p><a href="#" onclick="test(); return false;">test</a></p> <div id="content"></div> </body> </html> Internet Explorer 以外のブラウザ用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <html> <head> <script type="text/javascript"> function test(){ var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4) { alert(req.status); } }; req.open("GET", "./content.txt", true); req.send(null); } </script> </head> <body> <p><a href="#" onclick="test(); return false;">test</a></p> <div id="content"></div> </body> </html> 結果は全てレスポンスコード 200 の OK となってしまった。次にサーバのログをみてみよう。 ...

2008年6月1日 · Toshimitsu Takahashi