Mochikitも好きですが、普段はRails使いということもあってprototype.jsを使っています。
そういえばjavascriptのライブラリでOOなもの、ということで初めて出会ったのはjsolaitでした。 当時の印象としては「んー確かにがんばってるんだけど・・・ちょっと大げさっていうか・・・」って感じでした。
そして去年、prototype.jsに出会うわけですが「class-style OO」とうたっている部分がかなりシンプル(すぎ)で衝撃でした。
ただ、やっぱりjavascriptにおいて「継承」というのはやっかいな問題です。 というわけで誰か作ってると思うんですが、より簡単に継承できるライブラリを作ってみました。
Class.def = function(definition) {var klass = Class.create();if(definition.__extend__)Class.inherit(klass, definition.__extend__);if(definition.__static__)Object.extend(klass, definition.__static__);if(definition.__include__) {if(definition.__include__.constructor != Array)definition.__include__ = [definition.__include__];definition.__include__.each(function(include){Object.extend(klass.prototype, include);});}["__static__","__extend__","__include__"].each(function(n){delete definition[n];}Object.extend(klass.prototype, definition);return klass;}Class.inherit = function(child, parent) {Object.extend(child, parent);child.__super__ = parent.prototype;var dummy = function(){};dummy.prototype = parent.prototype;child.prototype = new dummy();child.prototype.constructor = child;return child;}
こんだけです。 使い方はサンプルをみるほうがわかりやすいと思うので、サンプルをどーぞ。
var IncludedClass = Class.def({__static__ : {includedMethod : function() {return "includedMethod:"+this.value;}}});var AClass = Class.def({__include__ : IncludedClass,__static__ : {A : "A static"},initialize : function(val) {if(!val) throw "error";this.val = val;this.klass = "AClass";},inspect : function() {return "< "+this.klass+" : "+this.val+">";}});var BClass = Class.def({ __extend__ : AClass,__static__ : {B : "B static"},initialize : function(val) {BClass.__super__.initialize.call(this, val);this.klass = "BClass";}});var CClass = Class.def({ __extend__ : BClass,__static__ : {C : "C static"},initialize : function(val) {CClass.__super__.initialize.call(this, val);this.klass = "CClass";}});var a = new AClass("aaaaaaa");var b = new BClass("bbbbbbb");var c = new CClass("ccccccc");alert("a inspect:"+a.inspect()); //=> a inspect:alert("b inspect:"+b.inspect()); //=> b inspect:alert("c inspect:"+c.inspect()); //=> c inspect:alert("includedMethod:"+a.includedMethod()); //=> includedMethod:included aaaaaaalert("CClass.A:"+CClass.A); //=> CClass.A:A staticalert("CClass.B:"+CClass.B); //=> CClass.B:B staticalert("CClass.C:"+CClass.C); //=> CClass.C:C staticalert("b.constructor = a.constructor:"+(b.constructor == a.constructor).toString()); //=>b.constructor = a.constructor:falsealert("b instanceof BClass:"+(b instanceof BClass).toString()); //=>b instanceof BClass:truealert("b instanceof AClass:"+(b instanceof AClass).toString()); //=>b instanceof AClass:truealert("c instanceof BClass:"+(c instanceof BClass).toString()); //=>c instanceof BClass:truealert("c instanceof AClass:"+(c instanceof AClass).toString()); //=>c instanceof AClass:true</div>
継承の処理がかなり楽になっていると思います。 テキトーに場当たりで単純にnewを使って継承していたりすると
「親クラスのコンストラクタに必須な引数があって、それがないとエラーでるから継承できねーよ、しゃーない適当に引数付けとくか」
ということになったりするもんですが(俺はよくなってますw)このライブラリを使えば大丈夫。 また、こんな変な書き方イヤだよ!!って方でも継承の部分はClass.inheritに独立させてあるのでそこだけつかえばオッケーです。
一応動作は確認していますがおかしいところあったら報告していただけるとありがたいです。