基底クラスのコンストラクタを呼び出す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"

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※投稿には管理者が設定した質問に答える必要があります。

名前:
メールアドレス:
URL:
次の質問に答えてください:
「ハイパーテキストマークアップ言語」をアルファベット4文字でいうと?

コメント:

トラックバック

このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2005/12/05/166280/tb

_ JavaScriptっぽい。 - 2005年12月08日 22時18分


【JavaScript】多重に派生されたクラスのコンストラクタで,基底クラスのコンストラクタを呼び出す方法。
なぜ2番目のコードでダメかというと、prototypeを書き換えれば、当然constructorもprot

_ Graviness Blog - 2005年12月11日 16時19分

前回の続き.先ず,3件のトラックバックと解決方法を頂いたことに感謝.以下に時系列で示す.

0. 多重に派生されたクラスのコンストラクタで,基底クラスのコンストラクタを呼び出す方法@Graviness Blog
1. 基底クラスのコンストラクタを呼び出す@Days on the Moon
2. 継承元のコンストラクタを順々に呼び出す。@JavaScriptっぽい。
3. 基底クラスコンストラクタ呼び出しの落とし穴@Days on the Moon

nanto_viさん,PURESTさんありがとう!

さて,上記一連の記事を読んでもらうと分かりますが,以下の方法が良いと判断しました.このコードは達人でもなかなか書けない代物ですよ!凄い!/**
* 継承関数.
* @param subClass 派生クラス
* @param superClass 基底クラス
*/
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;
    };
}



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);