前回の試行錯誤中に気がついたアイデア。クロージャでクラス定義すればthisとか煩わしくなくて良いのではないかという説。名づけて、クロージャベース・オブジェクト指向。
function Person(_name) {
var methods = {
__constructor: function() {name = _name; },
getName: function() { return name ; },
getType: function() { return "Person"; }
};
methods.__constructor();
return methods;
}
function Programmer(_name) {
// extends
var methods = Person(_name);
// override
methods["getType"] = function() { return "Programmer"; };
methods.__constructor();
return methods;
}
var psn = Person("Tom");
alert(psn.getName()); // Tom
alert(psn.getType()); // Person
var prg = Programmer("Jim");
alert(prg.getName()); // Jim
alert(prg.getType()); // Programmer
結構まともに動いちゃったりして。インスタンスごとにメソッド用のクロージャを保持するのでメモリ効率は悪いかもしれない。ちなみに、メンバ変数は全部protected強制、メソッドはpublicとprivateの使い分けができるっぽい。
実際使い物になるかどうかは謎。
最後にalert(psn.getName());を追加するとJimになるし、やっぱり駄目っぽい。
alert( name ) // Jim
突っ込みありがとうございます。やはりまともに動きませんね……。
"最後にalert(psn.getName());を追加するとJimにな"るのは name がグローバルで共有されてるからなので、それが困るなら function Person(name_) の実装のアタマで var name; と縛るやり方はありますね。
改良してみました。これでprivate,protected,public全ていけるんじゃないでしょうか?
function Person(){
var _private = {};
var _protected = {type : 'Person'};
var _public = {
__constructor : function(_name){_private.name = _name;},
getName : function(){return _private.name;},
getType : function(){return _protected.type;}
};
if(this == arguments.callee){
return {'_protected' : _protected , '_public' : _public};
}else{
_public.__constructor.apply(_public , arguments);
return _public;
}
}
Person.inherit = Person;
function Programmer() {
// extends
var superClass = Person.inherit();
var _protected = superClass._protected;
var _public = superClass._public;
// override
_protected.type = 'Programmer';
_public.__constructor.apply(_public , arguments);
return _public;
}
上のコメントを汎用的に使えるようにしてみました。拙 blog にて解説しています。
http://yudai.arielworks.com/memo/2005/07/24/151645.trackback
末尾に「5 + 0」の計算結果を繋げて下さい。例えば計算結果が「17」の場合、「151645.trackback17」です。これは機械的なトラックバックスパムを防止するための措置です。