◆ ちゃんとifを1機能としてつくるとjQueryの構造書きかえることになった
◆ findなどでstackに積まれる機能を利用して作ったので良さそう? 

ifメソッド欲しい

jQueryのメソッドチェーンでかけるところはいいところだと思ってます
ですが 書いてるとifが欲しいと思ってきます
var jqelem = $(".sample")
flag1 && jqelem.attr("id", id)
!flag1 && jqelem.append(chldelem)
flag2 && flag3 && jqelem.removeClass(cls)
メソッドチェーンしたい!
$(".sample")
.if(flag1)
.attr("id", id)
.else()
.append(chldelem)
.endif()
.if(flag2 && flag3)
.removeClass(cls)

こんな感じに書きたいです
ですが この書き方をできるようにできるifメソッドをextendでつくるのは無理そうです

if else で今がメソッドを実行するかの情報を持っておいて すべてのメソッドで実行時に確認する必要があります
さらに if 文のネストを考えるとtrue/falseの値をスタック状に持っておかないといけないです


普通 if をjQueryで作るとすると↓のようになりそうです
$(".sample").if(flag1, function truefn($this){
$this.attr("id", id)
}, function falsefn($this){
$this.append(chldelem)
}).if(flag2 && flag3, function truefn($this){
$this.removeClass(cls)
})
これだとifメソッドだけで完結しています
第一引数によって第二引数か第三引数の関数があれば実行するだけです

ですが これだとメソッドチェーン感が減るので上のみたいにしたいです

なんとか作ってみる

var obj = {
if: function(v){
this._if_stack || (this._if_stack = []);
this._if_stack.push(!!v);
return this;
},
endif: function(){
this._if_stack.pop();
return this;
},
else: function(){
this._if_stack.push(!this._if_stack.pop());
return this;
},
unless: function(){
this.if(!v);
return this;
},
};
var jqproto = $.fn.init.prototype;
for(var i in jqproto){
if(typeof jqproto[i] === "function"){
obj[i] = function(name){
return function(){
this._if_stack || (this._if_stack = []);
if(this._if_stack.length === 0 || this._if_stack.slice(-1).pop()){
return jqproto[name].apply(this, arguments);
}
return this;
};
}(i);
}
}
obj.__proto__ = jqproto;
$.fn.init.prototype = obj;

すごく無理矢理やってます

$() で返ってくるjQueryオブジェクトがメソッドを呼ぶときは__proto__を辿って $.fn.init.prototype を見ています
そこを
{$()} ---> {$fn.init.prototype}
{$()} ---> {ラップ用オブジェクト} ---> {$fn.init.prototype}
のようにプロトタイプチェーンを書き換えます

そして $fn.init.prototype にあるプロパティからすべての関数を 同じ名前でラップ用オブジェクトにプロパティを作ります
中身はstackの一番上を見てtrueなら $fn.init.prototype の同じ名前の関数を実行して false なら何もしないこれだけです

if, else, endif, unless のメソッドでは引数を見てスタックを編集だけします
スタックはjQueryオブジェクトごとに必要なのでなければ作るようにしておきます

これだけのためにjQueryの構造書き換えてるわけなので 良い拡張とは呼べそうにないです
ifメソッドを作るタイミングで そのときに存在する全関数をラップするようにしてますが その後にextendで追加されたものは対応できてないです

もっといい方法は・・・


なんかいい方法は~~・・・

んーー・・・・


・・・・・・・・・


・・・・・・・・・・・・



・・・・・・・・・閃いた!

jQueryってjQueryオブジェクトが空でもメソッドは実行できてその場合は何も実行されないです
それに find などでは stackに積まれて end でstackから降ろされます

これは使える!!!
$.fn.extend({
if: function(ifval){
if(ifval){
return this.filter("*")
}else{
return this.eq(this.length)
}
},
elseif: function(ifval){
return this.else().if(ifval)
},
else: function(){
var is_if_true = this.length > 0
return this.end().if(!is_if_true)
},
});

if では 引数がtrueなら中身そのままでstackに積まれるようにfilterですべての "*" を指定しています
false なら空になるように eq で存在しないところを指定しています

else では stackから1つおろして 逆の値をstackに積むようにします

endif の代わりが end で本来の機能そのままで使えます

elseif というのも作りましたが 中身は else if を順番にやってるだけです
必要な end の数が増えてわかりづらいので使わないほうがいいかと思います
if().else().if().end().end() と同じなので if().elseif().end().end() としないといけないです

jQueryのstack機能を使ってるだけなので if end の対応がずれるとおかしな動きをしてしまいますし 特にエラーも出ないので対応には気をつけないといけないです
また プロトタイプチェーン書き換えの方法と違って最後に end がないと返り値が空になる場合があります

こっちの方法だと余計なところに手を加えてないので問題なく使えそうです
たぶん

結局

プロトタイプチェーン書き換えの方法では 各メソッド実行時にifの条件となる値を確認していたので 関数を条件として渡して毎回実行と拡張することもできます
それができると if中にフラグとなる値を更新させて途中から実行するしないを変更したり else の方も実行したくなったときに両方実行させるなんてこともできます
高機能にはなりそうですが jQueryの構造書き換えてまでやる必要があるのか 微妙なところです

普通にifを使うだけなら下の方法でいいかと思います