2006 年 8 月 5 日 0 時 10 分

継承の実践 #2


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


Error インスタンスをプロトタイプとすると、
目に見えない悪影響を及ぼす可能性があることが分かった。

では次の手を考えてみよう。

Error プロトタイプを参照するオブジェクトを得るためには、
Error プロトタイプを prototype プロパティにもつ、
コンストラクタからインスタンスを作成するしかない。

Error インスタンスもこれに該当するが、
Error コンストラクタがどういう処理を行うかが、
分からないので問題が起きる可能性があった。

それならば、Error コンストラクタではなく、
悪影響を及ぼさないコンストラクタを使えばいい。

つまり、適当な型のコンストラクタを用意し、
コンストラクタの prototype プロパティを、
Error プロトタイプに設定してやればよいのだ。

そうすると、その型から作成されたインスタンスは、
Error プロトタイプをプロトタイプとして持つはずである。

    // ダミー型なので、コードは不要
    function ErrorInheritor() {
    }

    // ErrorInheritor のインスタンスは、
    // Error プロトタイプをプロトタイプとして参照する
    ErrorInheritor.prototype = Error.prototype;

    function MixiError(message) {
        // 省略
    }

    // ErrorInheritor インスタンスをプロトタイプとする
    MixiError.prototype = new ErrorInheritor();
    MixiError.prototype.constructor = MixiError;

    // name には例外型の名前が入る。
    MixiError.prototype.name = "MixiError";

    // その他のプロトタイププロパティの設定など
    MixiError.prototype.hoge = "fuga";

ErrorInheritor プロトタイプとして、
Error プロトタイプを代入している。
これによって、ErrorInheritor インスタンスは、
Error プロトタイプを参照するようになる。

つまり、以下のようなチェーンとなる。

    MixiError インスタンス
        ⇒MixiError プロトタイプ(=ErrorInheritor インスタンス)
            ⇒Error プロトタイプ
                ⇒Object プロトタイプ

昨日と違うのは、ErrorInheritor インスタンスだ。

ErrorInheritor コンストラクタは空だ。
そのため、ErrorInheritor インスタンスを作成しても、
Error インスタンスの作成と違い、何の問題も生じない。

ErrorInheritor インスタンスにはプロパティもないので、
純粋な MixiError プロトタイプとして利用が可能となる。

ただ、ErrorInheritor は、通常の型ではなく、
プロトタイプのチェーンを実現するだけの型である。
なので、ErrorInheritor コンストラクタや、
ErrorInheritor プロトタイプが改変されると困る。

特に、ErrorInheritor プロトタイプとして、
Error プロトタイプ「そのもの」を使っているので、
ErrorInheritor.prototype にプロパティを設定されると、
それは、Error プロトタイプにも反映されてしまい、
意図せずに Error インスタンスに影響を与えてしまう。

これを防ぐためには、ErrorInheritor 型を、
一時的に生成する方法を使えばいい。

    function inherit(derived, base) {

        // 一時的なコンストラクタ作成
        var Inheritor = function() {};

        // Inheritor のインスタンスは、
        // 基底プロトタイプをプロトタイプとして参照する
        Inheritor.prototype = base.prototype;

        // Inheritor インスタンスをプロトタイプとして、
        // 基底プロトタイプをチェーンに追加する
        derived.prototype = new Inheritor();

        // constructor プロパティのルールに従う
        derived.prototype.constructor = derived;
    }

    function MixiError(message) {
        // 省略
    }

    // 継承
    inherit(MixiError, Error);


    // name には例外型の名前が入る。
    MixiError.prototype.name = "MixiError";

    // その他のプロトタイププロパティの設定など
    MixiError.prototype.hoge = "fuga";

上記では、Inheritor コンストラクタは、
inherit 関数内で一時的に生成される。

new Inheritor() でインスタンスが作成されても、
インスタンスが持つ参照は Error プロトタイプである。

なので、inherit 関数を抜けた時点で、
参照されなくなった Inheritor コンストラクタは消滅する。

こういう風に設計することで、
やっとプロトタイプの継承が行えたというわけだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.