6

スーパークラスとして機能するコンストラクター関数が1つあります。

Bla = function(a){this.a = a;}

簡単な方法を含めるためにプロトタイプを作成します。

Bla.prototype.f = function(){console.log("f");

そして今、newBla(1).f();はコンソールに「f」を記録します。しかし、Blaから継承するサブクラスが必要だとしましょう。

Bla2 = function(a)
{
    this.base = Bla;
    this.base();
}

x = new Bla2(5);

今、予想通り、私にx.a与えます5。しかし、x.fですundefined!クラスBla2から継承しなかったようです!Blaなぜこれが起こっているのですか、どうすれば修正できますか?

4

1 に答える 1

30

クラスBla2から継承しなかったようです!Bla

右。そこに継承をフックするために何もしていません。インスタンスであるBla2calledのメンバーを作成しただけです。JavaScriptの特別な識別子ではありません。baseBlabase

JavaScriptで継承を設定する一般的な方法は、次のようになります。

// The base constructor function
function Base(x) {
    // Base per-instance init
    this.x = x;
}

// An example Base function
Base.prototype.foo = function() {
    console.log("I'm Base#foo, x = " + this.x);
};

// The Derived constructor function
function Derived(x, y) {
    // Normally you need to call `Base` as it may have per-instance
    // initialization it needs to do. You need to do it such that
    // within the call, `this` refers to the current `this`, so you
    // use `Function#call` or `Function#apply` as appropriate.
    Base.call(this, x);

    // Derived per-instance init
    this.y = y;
}

// Make the Derived.prototype be a new object backed up by the
// Base.prototype.    
Derived.prototype = Object.create(Base.prototype);

// Fix up the 'constructor' property
Derived.prototype.constructor = Derived;

// Add any Derived functions
Derived.prototype.bar = function() {
    console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
};

... Object.createES5からのものですが、ほとんどの場合簡単にシムできるものの1つです。(または、すべてを実行しようとせずに最小限の関数のみを実行する関数を使用できますObject.create。以下を参照してください。)次に、それを使用します。

var d = new Derived(4, 2);
d.foo(); // "I'm Base#foo, x = 4"
d.bar(); // "I'm Derived#bar, x = 4, y = 2"

実例| ソース

古いコードでは、Derived.prototype代わりに次のような設定が表示されることがあります。

Derived.prototype = new Base();

...しかし、そのようにすることには問題があります。インスタンスごとの初期化を行う可能性がありますが、これは全体が継承するBaseのに適切ではありません。Derived引数が必要な場合もあります(私たちのBaseように、何を渡すのxでしょうか?)。代わりにDerived.prototype、に裏打ちされた新しいオブジェクトBase.prototypeにすることで、正しいものを取得できます。次に、インスタンスごとのinitを取得するためにBase内部から呼び出します。Derived

上記は非常に基本的なものであり、ご覧のとおり、いくつかの手順が含まれます。また、「スーパーコール」を簡単で保守性の高いものにするために、ほとんどまたは何もしません。Classそのため、Prototype 、Dean Edwards、Base2、または(咳)自分のスクリプトなど、非常に多くの「継承」スクリプトが表示されLineageます。


ご使用の環境にES5機能があることに依存できず、の基本を実行するシムを含めたくないObject.create場合は、代わりにこの関数を使用できます。

function simpleCreate(proto) {
    function Ctor() {
    }
    ctor.prototype = proto;
    return new Ctor();
}

その後、代わりに

Derived.prototype = Object.create(Base.prototype);

あなたがするだろう:

Derived.prototype = simpleCreate(Base.prototype);

もちろん、接続を自動化するためにさらに多くのことを行うことができます。これはLineage基本的にすべてです。


...そして最後に:上記では簡単にするために匿名関数を使用しました。例:

Base.prototype.foo = function() {
    // ...
};

...しかし、実際のコードではそれを行いません。ツールが私を助けてくれるのを助けたいからです。そのため、各「クラス」(コンストラクター関数と関連するプロトタイプ)の周りにモジュールパターンを使用し、関数宣言を使用する傾向があります(Webで作業しているため、IE7とIE8でも名前付き関数式に問題があります。を使用してLineage、私は次のように上記を行います:

// Base
(function(target) {
    // Base constructor
    target.Base = Base;
    function Base(x) {
        // Base per-instance init
        this.x = x;
    }

    // An example Base function
    Base.prototype.foo = Base$foo;
    function Base$foo() {
        console.log("I'm Base#foo, x = " + this.x);
    }
})(window);

// Derived
(function(target, base) {
    // The Derived constructor function
    target.Derived = Derived;
    function Derived(x, y) {
        // Init base
        base.call(this, x);

        // Derived per-instance init
        this.y = y;
    }

    // Make the Derived.prototype be a new object backed up by the
    // Base.prototype.    
    Derived.prototype = Object.create(base.prototype);

    // Fix up the 'constructor' property
    Derived.prototype.constructor = Derived;

    // Add any Derived functions
    Derived.prototype.bar = Derived$bar;
    function Derived$bar() {
        console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
    }
})(window, Base);

...またはそのようなもの。ライブコピー| ソース

于 2012-06-17T15:44:06.423 に答える