2015-09-16 13 views
24

私は期待して何のJavaScript(ES6)コール親関数(ES6)

class A{ 
    constructor(){ 
    this.foo(); 
    } 
    foo(){ 
    console.log("foo in A is called"); 
    } 
} 

class B extends A{ 
    constructor(){ 
    super(); 
    this.foo(); 
    } 
    foo(){ 
    console.log("foo in B is called"); 
    } 
} 

して、以下の問題が発生しました

foo in A is called 
foo in B is called 

ですしかし、実際に、それは私が単にクラスにsuper.foo()を追加することによってこの問題を解決することができます知っている

foo in B is called 
foo in B is called 

ですBの関数foo

class B extends A{ 
    constructor(){ 
    super(); 
    this.foo(); 
    } 
    foo(){ 
    super.foo() // add this line 
    console.log("foo in B is called"); 
    } 
} 

しかし、これと同様のシナリオを想像:

子供はいくつかの余分な作業を行うと、外側が元にアクセスできることからアクセスを防止するために、親の関数をオーバーライドする必要があります。

class B extends A{ 
    constructor(){ 
    super(); 
    this.initBar(); 
    } 
    foo(){ 
    super.foo(); 
    this.bar.run(); //undefined 
    console.log("foo in B is called"); 
    } 
    initBar(){ 
    this.bar.run = function(){ 
     console.log("bar is running"); 
    }; 
    } 
} 

Aで構築中thisはまだ子供Bを指しているようです。だから私は親に到達することができませんAfoo

thisは、コンストラクタチェーン中に子によってオーバーライドされる親バージョン関数を呼び出すにはどうすればよいですか?

また、このようなシナリオになると、より良い解決策がありますか?

編集

だから、答えを読んだ後、メインの質問はなった -

それは子供たちがそれらを上書きする機会を持っているので、JavaScriptでコンストラクタでinitialize helperssetter functionsを入れてがっかりですか?

より明確な状況明確にする:(私の以前の悪い例:(申し訳ありませんが)

class A{ 
    constructor(name){ 
    this.setName(name); 
    } 
    setName(name){ 
    this._name = name; 
    } 
} 

class B extends A{ 
    constructor(name){ 
    super(name); 
    this._div = document.createElementById("div"); 
    } 
    setName(name){ 
    super.setName(name); 
    this._div.appendChild(document.createTextNode(name)); 
    } 
} 

new B("foo") 

this._divundefinedなります

が、これは子供が上書きすることができるようになりますので、悪い考えです。機能?

class A{ 
    constructor(name){ 
    this.setName(name); // Is it bad? 
    } 
    ... 
} 

だから私はconstの中initialize helperssetter functionsを使用しないでくださいJava、C++のようなルーダ...?

私は物事を初期化するためにこのnew A().init()のようなものを手動で呼び出す必要がありますか?

+0

*親バージョンの関数を呼び出すには 'this'をどうすればいいですか? - ' super'が唯一の方法です。 – thefourtheye

+0

なぜ 'A'コンストラクタは' this.foo() 'を全く呼びますか?インスタンスを初期化するだけでよいはずはありません。 – Bergi

+0

子の 'foo'は、一般的な原因で親の実装をオーバーライドすることを意味しますか、または" foo "をプライベートヘルパーにする方法をもっと求めていますか? – loganfsmyth

答えて

9

派生クラスBのコンストラクタにあるときに、ABの2つのオブジェクトがあると誤解されているようです。これはまったく当てはまりません。 1つのオブジェクトしかありません。 ABの両方がその1つのオブジェクトにプロパティとメソッドを提供します。それはクラスBのオブジェクトの作成中Aのコンストラクタであるようthisの値がBのコンストラクタで同じになる

ES6クラス構文はのためのプロトタイプを使用ES5法上だけ糖であります実際には、プロトタイプはまだカバーの下で使用されています。そのため、クラスBのように派生クラスにメソッドfooを定義すると、それはまだプロトタイプに割り当てられており、その割り当ては、親定義からのプロトタイプに既に存在する可能性のある同じ名前のメソッドをオーバーライドします。このため、this.foo()はBクラスのバージョンfooを指しています。 fooのクラスAのバージョンに到達する場合は、既に知っているようにsuperを使用して手動で指定する必要があります。あなたの具体的な質問については

私が親AのFOOに到達できない理由です 親Aに構築しながら、これはまだ子Bを指すようです。

子Bと親Aは別々のオブジェクトではありません。親Aと子Bの両方が参照するオブジェクトが1つあります。親Aおよび子Bのメソッドまたはコンストラクタには、同じ値のthisが表示されます。

コンストラクタチェーンで子によってオーバーライドされた の親バージョン関数を呼び出すにはどうすればよいですか?

superは、すでに知っているように親メソッドを直接参照するために使用します。

また、このようなシナリオではもっと良い解決策がありますか?

superが解決策です。


FYI、これはどのようにsuper作品を含むES6クラスのかなり良い議論がある:Classes in ECMAScript 6 (final semantics)。セクション4.4はあなたの質問/理解に特に関係しているようです。

+0

"this.setName(name);"のような親コンストラクタでsetterを使用しない方が良いと思います。 this.name = name;を使用する方が良いでしょう。このようにsuper()を使用すると、気付かないオーバーライド関数は使用されません。 – llioor