基底クラスのコンストラクタを呼び出す ― 2005年12月05日 00時06分
「【JavaScript】多重に派生されたクラスのコンストラクタで,基底クラスのコンストラクタを呼び出す方法」(Graviness Blog) にて基底クラスのコンストラクタを呼び出すという話題が出ていた。優乃さんは this
から基底クラスのコンストラクタを呼び出したいようだが、JavaScript では this
が何をさすかは文脈により異なってくる (「ECMAScript における this の意味」(Noncommutative Field) を参照)。なので個人的には基底クラスに関する操作はインスタンス (this
) よりもクラス (コンストラクタ関数) から行ったほうがいいと思う。クラス名に依存したくないなら arguments.callee
を用いればよい。
function Animal() {} // 基底クラス
function Dog() {
this.__super__(); // this が何であるか (this.__super__ が何をさすか) は不定
}
function Cat() {
Cat._superClass.apply(this); // クラス名に依存
}
function Swallow() {
arguments.callee._superClass.apply(this); // クラス名に非依存、でもちょっと長い?
}
しかし実際に書き比べてみるとやはり this
から呼び出せたほうが見通しがいいわけで。this
から呼び出す際の問題は基底クラスのコンストラクタ内でも this.__super__
が変わらず、それ以上上のクラスのコンストラクタを呼び出せないこと。ならば基底クラスのコンストラクタを呼び出すときだけ __super__
を書き換えてやればいいのではないか。こんな感じで。
function inherit(subClass, superClass) {
var Temp = new Function();
Temp.prototype = superClass.prototype;
subClass.prototype = new Temp;
subClass.prototype.constructor = subClass;
subClass.prototype.__super__ = function () {
var originalSuper = this.__super__;
this.__super__ = superClass.prototype.__super__ || null;
superClass.apply(this, arguments);
if (this.constructor == subClass)
delete this.__super__;
else
this.__super__ = originalSuper;
};
}
個人的に Class.prototype.constructor == Class
というのは常に成り立っていてほしいのでそのように修正。基底クラスのコンストラクタ内で this.method()
としても SuperClass#method
ではなく SubClass#method
が呼び出されるなどの不具合はあるが、コンストラクタ関数だけで完結する処理ならこれでうまく行くと思う。
function SuperSuperClass() {
alert("SuperSuperClass Constructor");
this.p = "supersuperclass";
}
function SuperClass() {
alert("SuperClass Constructor");
this.__super__(); // SuperSuperClass のコンストラクタを呼び出す.
this.q = "superclass";
}
function SubClass() {
alert("SubClass Constructor");
this.__super__(); // SuperClass のコンストラクタを呼び出す.
this.r = "subclass";
}
// 継承
inherit(SuperClass, SuperSuperClass);
inherit(SubClass, SuperClass);
var a = new SubClass();
alert(a.p); // "supersuperclass"
alert(a.q); // "superclass"
alert(a.r); // "subclass"
最近のコメント