JavaScriptとクロージャとデザインパターン
html5-developers-jpで「GoFデザインパターンのJavascript版があったら様相がかわるかも?」という話が出ました。
デザインパターンが拡張性を確保する手段の一つがメソッドの書き換えなのですが、Javavscriptの場合、通常の継承とは違う特有のメソッドのオーバーライト方法があります。
var sample_class=function(){}; sample_class.prototype.exec=function(){ this.do_a(); this.do_b(); }; sample_class.prototype.do_a=function(){ alert("a"); }; sample_class.prototype.do_b=function(){ alert("b"); }; var sample=new sample_class(); sample.exec()//"a","b" //do_a,do_bを書き換える sample.do_a=function(){ alert("b"); }; sample.do_b=function(){ alert("a"); }; sample.exec()//"b","a" //thisも使える sample.b="c"; sample.do_b=function(){ alert(this.b); }; sample.exec()//"b","c"
Javascriptでは、関数はオブジェクトです。また、Javascriptではthisは呼び出し方に依存します。なので、このように後付で関数オブジェクトを代入することでクラスを継承してメソッドを書き換えた場合と同じことが出来てしまいます。
これだけでもその場でしか使わないような細かい変更がある場合には便利なのですが、クロージャと組み合わせるとさらに強力になります。
一例としてテンプレートパターンで考えます。
//特定のDOMの文字色を変更する処理をテンプレート化 var basic_template=function(elem){ this.elem=elem; }; basic_template.prototype.exec=function(){ var elem=this.getElem(); var color=this.getColor(); elem.style.color=color; }; basic_template.prototype.getElem=function(){ return this.elem; }; basic_template.prototype.getColor=function(){ return this.color; };
これをクリックに応じて順番に文字色を変えられるようにする場合、こんな書き方が可能になります。
//colorsは文字色を表す文字列を要素とするリスト。 function rotate_change(elem,colors){ var template=new basic_template(elem); //常に先頭を返す template.getColor=function(){ return colors[0]; }; //クリック処理 elem.onclick=function(){ template.exec(); var head=colors.shift(); colors.push(head); } }
こんな感じで、メンバーへの関数オブジェクトの代入がそのままオーバーライトとなる性質と、クロージャという閉じ込められたグローバル変数を利用することでコンパクトな書き方が可能になるのが特徴です。
昨日も書いたとおり、特にこのクロージャを閉じ込められたグローバル変数として使うというのは非常に重要で、イベント処理がかなり単純化します