2016-07-07 10 views
1

クラス指向言語とは対照的に、JSはプロトタイプベースであり、オブジェクトのコンストラクタは "コンストラクタロジック"(私はこの用語をMDNで見つけました)だけでなく、特権メソッドも定義します。 1つの "クラス"が別のクラスの子である場合(残念ですが、私はJSの "クラス"よりも良い言葉がわかりません)、これは子クラスがオーバーライドする前に親コンストラクタが実行されるかまたはコンストラクタがまだ実行されていないため、子クラスはメソッドをオーバーライドできません。Javascript:子クラスの継承されたメソッドをオーバーライドした後、親クラスのコンストラクタロジックを実行するにはどうすればよいですか?

私が意味するものを説明するための例を挙げます。オブジェクトの特権関数を定義する「親クラス」と、このメソッドを呼び出すコンストラクタロジックを想定します。

function Parent() { 
    this.methodA = function() { 
    // do something 
    }; 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

methodAを再定義するが、それでも親クラスのコンストラクタ ロジックを使用しなければならない子クラスを想定します。

最初のアプローチは、子コンストラクタ の先頭に親コンストラクタを呼び出すことです。しかし、親コンストラクタは依然として親の 実装を呼び出します。

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Call parent constructor first. Problem: The parent constructor 
    // calls methodA before it will be overriden by child constructor 
    Parent.call(this); 

    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and then call parent method 
    _oldMethodA.call(this); 
    }; 
} 

第2のアプローチは、親メソッドをオーバーライドすることができない 後、しかし、その後、親のコンストラクタを呼び出すことです。特権メソッドの定義とコンストラクタロジック - - 正しい順序で呼び出されていますか?私はJSコンストラクタの両方のタスクをインターリーブするにはどうすればよい

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

function Child() { 
    // Override first. Problem: The parent constructor has not defined methodA 
    // yet, hence the line below fails. 
    var _oldMethodA = this.methodA; 
    this.methodA = function() { 
    // do something special and call parent method 
    _oldMethodA.call(this); 
    }; 

    Parent.call(this); 
} 

付録

- 追加の材料によるコメント

に私は私が欲しいものを明確にすることがないようだというコメントから考え出しました。そこでここではこれは次の出力

$> I do the work of the parent's method 
$> I do the work of the child's method and ... 
$> I do the work of the parent's method 

これは何が起こるかになり

class Parent { 
    public Parent() { 
    methodA(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the parent's method"); 
    } 
} 

class Child extends Parent { 
    public Child { 
    super(); 
    } 

    public void methodA() { 
    System.out.println("I do the work of the child's method and ..."); 
    super(); 
    } 
} 

Parent p = new Parent(); 
Child c = new Child(); 

のJava

で書かれた例があります。 Parentのコンストラクタは、 Parentで定義された methodAの実装を呼び出します。これは特別なものではなく、最初の出力行を生成します。 Childのコンストラクタは、前と同じように methodAを再度呼び出す親のコンストラクタを呼び出します。しかしながら、これは親のコンストラクタであるが、オブジェクトは依然として Childのインスタンスであるため、子クラスの methodAの実装が実行される。このメソッドは、2行目の出力を出力し、3行目を生成する親のメソッドを明示的に呼び出します。

これはOOPによると完全な正しい動作であり、これはJavascriptでも達成したいものです。実際はopposite of the problem mentioned hereです。リンクはコメントのものです。

+0

どこ 'methodB'はありますか? – Ben

+0

あなたの問題は、プロトタイプベースの継承や特権メソッドではなく、コンストラクタからオーバーライド可能なメソッドを呼び出すことにあります。それは私が見たどの言語でもうまくいきません。 – Bergi

+0

@BenAston:申し訳ありませんが、 'methodB'はコメントの入力ミスです。以前のバージョンの例では2つのメソッドを使用しましたが、MWEを1つのメソッドに煮詰めました。 – user2690527

答えて

-1

ない本当にあなたがここに達成したいが、一般的に、あなたがこのような何か行うことができいえば何をすべきかを確認します。

function Parent() { 
    if (this.methodA == null) { 
    this.methodA = function() { 
     // do something 
     console.log('parent'); 
    }; 
    } 

    // C'tor logic starts here 
    // Beside other things also call some method of this object 
    this.methodA(); 
} 

function Child() { 

    this.methodA = (function(_oldMethodA) { 
    return function() { 
     console.log('child'); 
     // do something special and then call parent method 
     if (_oldMethodA) { 
     _oldMethodA.call(this); 
     } 
    } 
    })(this.methodA); 

    Parent.call(this); 
} 

Child.prototype = Object.create(Parent.prototype); 
Child.prototype.constructor = Child; 

new Child(); // yields: 'child' 

をしかし、あなたが親で、いくつかの配列を追加したい場合がありますやりたいことに判断し、親クラスのメソッドAをオーバーライドしています。

+0

'Child'では' _oldMethodA'は常に 'undefined'です – Bergi

+0

いいえ、この"解決策 "は意味をなさない。 Bergiは '_oldMethodA'は' this.methodA'をパラメータとして呼び出される無名関数のパラメータであるが 'this.methodA'はまだ定義されているので、常に未定義であると述べています。このコードは、ある種の「自己参照」を示しています。 – user2690527

0

親クラスを呼び出す前に、プロパティを子クラスのアクセサとして定義できます。

この方法では、親クラスによって割り当てられた関数への参照を取得することができますが、引き続きゲッターで目的の関数を提供することができます。

function Parent() { 
 
    this.methodA = function() { console.log('Parent method'); }; 
 
    this.methodA(); 
 
} 
 
function Child() { 
 
    var _oldMethodA; 
 
    var _newMethodA = function() { 
 
    console.log('Code injected by Child'); 
 
    _oldMethodA.call(this); 
 
    }; 
 
    Object.defineProperty(this, 'methodA', { 
 
    configurable: true, 
 
    enumerable: true, 
 
    set: function(val){ _oldMethodA = val; }, 
 
    get: function(){ return _newMethodA; } 
 
    }); 
 
    Parent.call(this); 
 
    /* Optional: convert it back to a data property */ 
 
    Object.defineProperty(this, 'methodA', { 
 
    value: _newMethodA, 
 
    writable: true 
 
    }); 
 
} 
 
Child.prototype = Object.create(Parent.prototype); 
 
Child.prototype.constructor = Child; 
 
new Child();

+0

Urgh。私はちょっとこれがES6でもううまくいきません:-) – Bergi

+0

@Bergiはい、それは醜いコードです。しかし、私はそれがまだES6で動作するはずだと思います。 – Oriol

+0

私は達成したいと思うことをしているようで、私はこの解決策を考え出すために必要な創造性に敬意を表します。しかし、私はそれを使用したくないので、複雑です。申し訳ありません;-)コードはきれいで正確でなければなりません。 – user2690527

関連する問題