条件付メソッドチェーン実現のためjQueryのラッパーを作ってみた

今回作ったもの

testという名前のメソッドを呼ぶとそれ以降、
jQueryオブジェクトをラップしたオブジェクトによって
メソッドチェーンが繋がっていく。
jQueryオブジェクトを返さないメソッドを実行した場合には、
ラップしないで元のメソッドの戻り値を返す。

コード

(function($){

function JQWrapper(jQueryObj){
	this._jQueryObj = jQueryObj;
}
for(var i in $.fn){
	if(!$.isFunction($.fn[i]) || i == 'test')continue;
	(function(i){
		JQWrapper.prototype[i] = function(){
			console.log('methodName:'+i);
			console.log(arguments);
			console.log(this._jQueryObj.get());
			var result = $.fn[i].apply(this._jQueryObj,arguments);
			if(result instanceof $){
				return new JQWrapper(result);
			}else{
				return result;
			}
		};
	})(i);
}
$.extend(
	$.fn
	,{
		'test':function(cond){
			return new JQWrapper(this);
		}
	});

})(jQuery);

Firebug consoleから実行するの限定。
jQueryオブジェクトのメソッドを呼ぶと以下をconsoleに出力します。

  • メソッド名
  • メソッドが呼び出された際の引数
  • そのメソッドが呼び出された(ラップされたjQueryオブジェクト)が保持するDOM要素

試してみる

サンプルコード

$('<div/>')
	.test()
	.append('<span>hogehoge</span>')
	.append('<span>fugafuga</span>')
	.append('<span>piyopiyo</span>')
	.append('<span/>')
	.html()

実行結果

methodName:append
["<span>hogehoge</span>"]
[div]
methodName:append
["<span>fugafuga</span>"]
[div]
methodName:append
["<span>piyopiyo</span>"]
[div]
methodName:append
["<span/>"]
[div]
methodName:html
[]
[div]
"<span>hogehoge</span><span>fugafuga</span><span>piyopiyo</span><span></span>"

サンプルコード

$('<div/>')
	.test()
	.wrap('<div/>')
	.wrap('<div/>')
	.parent()
	.text('hogehoge')
	.attr('id','fuga')
	.parent()
	.html()

実行結果

methodName:wrap
["<div/>"]
[div]
methodName:wrap
["<div/>"]
[div]
methodName:parent
[]
[div]
methodName:text
["hogehoge"]
[div]
methodName:attr
["id", "fuga"]
[div]
methodName:parent
[]
[div#fuga]
methodName:html
[]
[div]
"<div id="fuga">hogehoge</div>"

それで今後どうするか?

jQueryオブジェクトではなくラッパーオブジェクトで
メソッドチェーンさせているので、
jQueryオブジェクトを汚染させずに状態を持たせることが出来る。
これと、今回試した処理の横取りを使って、

$(someCSSSelector)
	.If(someCond)
		.append('<span>hogehoge</span>')
		.append('<span>hogehoge</span>')
		.append('<span>hogehoge</span>')
	.ElseIf(otherCond)
		.append('<span>fugafuga</span>')
		.wrap('<div/>')
		.parent()
		.text('hogehoge')
		.attr('id','fuga')
	.Else()
		.empty()
	.EndIf()

↑こんな感じのコードにぱっと見騙されたとおりの動きをさせたい。