behaviour.js リバースエンジニアリング その1

話題のbehaviour.jsのソースを見ていきます。


behaviour.jsの使い方から

var myrules = {
		'b.someclass' : function(element){
			element.onclick = function(){
				alert(this.innerHTML);
			}
		},
		'#someid u' : function(element){
			element.onmouseover = function(){
				this.innerHTML = "BLAH!";
			}
		}
	};
	
Behaviour.register(myrules);

となっております。このエントリーではライブラリのソースを見てどんな仕組みで動いているかを検証するのが目的なので、もしライブラリの詳しい利用法が知りたいという方はこのスクリプトの紹介元である
【我的春秋さん】
http://my-chunqiu.cocolog-nifty.com/blog/2006/01/javascript_html_bc22.html
を参照してください。




ではでは。ソースを。A4用紙四枚分と長いので、まずは前半部分を参照します

var Behaviour = {
        //オブジェクトをプールするための配列 
	list : new Array,
	
    //list配列にオブジェクトをプールする
	register : function(sheet){
		Behaviour.list.push(sheet);
	},
	
        //behaviourオブジェクトでの処理の開始。
        //addLoadEvent()でonload時にapply()を開始する
	start : function(){
		Behaviour.addLoadEvent(function(){
			Behaviour.apply();
		});
	},

	//list配列にプールされたオブジェクトをひっぱりだして,
        //ユーザーの指定したセレクタを引数にしてgetElementsBySelectorを実行し
        //該当するHTMLエレメントに関数/ハンドラを割り当てていく
	apply : function(){
		for (h=0;sheet=Behaviour.list[h];h++){
			for (selector in sheet){
				list = document.getElementsBySelector(selector);
				
				if (!list){
					continue;
				}

				for (i=0;element=list[i];i++){
					sheet[selector](element);
				}
			}
		}
	},
	
        //window.onloadに関数を割り当てる。
	addLoadEvent : function(func){
		var oldonload = window.onload;
		
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	}
}

//処理の開始
//自動的に呼び出される
Behaviour.start();

上記が肝となるBehaviourオブジェクトのソースです。オブジェクトの中身は

  • list (Array) ... ユーザーが指定した「CSSセレクタ/関数」のオブジェクトをプールしておく配列。Behaviour.apply()中で呼び出される
  • register (Function) ... CSSセレクタ/関数のオブジェクトをlist配列にプールする関数。behaviour.jsを使う際にユーザーが呼び出す必要があるのはこの関数だけである。つまり唯一のAPIとして機能する。デザパタだとFacadeパターンかな?
  • start(Function) ... 全体の処理を開始する関数。具体的にはブラウザがJavascriptタグが解析している時にBehaviour.addLoadEvent()とBehaviour.apply()を呼び出す。ユーザーが明示的に呼び出す必要は無い。
  • apply (Function) ... Behaviour.listにプールされたオブジェクトを呼び出し、ユーザーの指定したセレクタに応じて関数/ハンドラを割り当てていく関数。
  • getElementsBySelector (Function) ... behaviour.js の核となる関数。これ大事。一見 DOMでサポートされたような関数に見えるけど、違います。この関数はソースの後半で定義されています。ユーザーの指定したCSSセレクタに対応する HTMLエレメントの配列を返す関数。
  • addLoadEvent(Function) ...  ページ読み込みが完了した際にBehaviour.apply()を呼び出す。つまり、window.onload でごにょごにょしてる。


Behaviourオブジェクトは ユーザーがセレクタで指定したHTMLエレメントに関数/ハンドラを割り当てる役目をはたしています。シンプルな実装ですね。


実際的な「指定されたセレクタ名を解析し、HTMLをパースして該当するエレメントを配列として返す」という煩雑な作業はgetElementsBySelector()の中でやっています。先に書いたようにgetElementsBySelector()はDOMでサポートされた関数ではなく、Simon Willison という人によって書かれたコードです。エラい!(詳しいことはソースのコメント部分を参照してください)

google検索 - getElementsBySelector】
http://www.google.co.jp/search?num=50&hl=ja&q=getElementsBySelector&ie=UTF-8&oe=UTF-8



ということで後半部分に書かれている一番大事なgetElementsBySelectorの中を見ないと意味が無いなー・・・でも、ちょっと用事が差し迫ってるのでまた後で書きます。
手元にリファレンス本が無く、また急いで書いてしまったので間違い/誤記があったらすいません。先に謝っとく!