2016-04-28 6 views
5

I持っているこれら二つの活字体のクラス:活字体オーバーライドされたクラスのメソッドと、この

class Base { 
    value: string; 

    lambdaExample =() => { 
    this.value = 'one'; 
    } 

    methodExample() { 
    this.value = 'two'; 
    } 
} 

class Child extends Base { 
    lambdaExample =() => { 
    super.lambdaExample(); // Error, because I've overwritten (instead of overridden) the method 
    this.value = 'three'; // ok 
    } 

    methodExample() => { 
    super.methodExample(); // ok 
    this.value = 'four'; // Error: this refers to window, not to the actual this 
    } 
} 

どのように私はthis参照が私はメソッドをオーバーライドしてからそれらを呼び出すことができ、信頼性があるように私の方法を記述します親クラス?

+0

[スーパークラスからオーバーライドされたメソッドをtypescriptで呼び出す]の可能な複製(http://stackoverflow.com/questions/30819663/call-an-overridden-method-from-super-class-in-typescript) – smnbbrv

+1

重複ではない:その質問は、クラスプロパティを使ってオーバーライドされたメソッドについてではなく、コンストラクタでクラスメソッドを呼び出すことに関するものです。 – Jorn

+0

@smnbbrvこの質問は、この問題とは関係ありません。 –

答えて

2

実際には、Microsoft's Git Wikiにこの問題に取り組むさまざまな方法をよく見ています。

  • 継承を気にする場合は、別のコンテキストから呼び出されるたびにメソッドをバインドまたはラップします。
  • メソッドを、関数を含むプロパティに変換します。

実際のWikiにはさらに多くの規定があり、私は本当にすべてを読むことをお勧めします。

EDIT

ラッピングの例:あなたはクリックハンドラ(例えば)からsomeMethodを呼び出すようにした場合はクラス

class SomeClass { 
    public someProp: string = "Hello World"; 

    public someMethod() { 
     console.log(this.someProp); 
    } 

} 

考える

- someEl.onclick = instanceOfMyClass.someMethod; - 例外だろう(と仮定してwindowにはプロパティがありませんsomeProp )。

あなたは(事実上、とにかく、何バインドを行っている)のいずれか(タイプセーフではないES6の互換性はありません、) instanceOfMyClassに関数を結合することによって、または手動でそれをラップすることにより、これを回避することができ

:それは少しだ

someEl.onclick = function() { 
    someInstanceOfMyClass.someMethod(); 
}; 

someMethodsomeInstanceOfMyClassのプロパティとして呼び出し、それをイベントハンドラに渡さないと(windowのプロパティに変わります)、thisが常にMyClassのインスタンスであることが保証されます。

+0

ラッピング方法が少し不明です。この作品のようなものはありますか? 'class child {methodExample(){var wrap =()=> {super.methodExample()};ラップ(); } ' – Jorn

+0

ラッピングは、別のコンテキストから関数を呼び出すたびに実行するという点でbindと似ています。例えば、与えられたクラス 'class MyClass {public someMethod(){console.log(this); }} ''(this)=> {instanceOfMyClass.someMethod()})() 'のように' this 'を別のコンテキストから 'MyClass'のインスタンスにするには、このように呼び出すことができます。重要なことは、メソッドを直接渡すのではなく(インスタンスのコンテキストを変更する)、メソッドを 'instanceOfMyClass'のプロパティとして呼び出すことです。 –

1

エラーが間違っている理由についてのあなたの前提は、私​​があなたの問題の原因だと思っています...少なくとも私はそれを理解しています。例えば

lambdaExample =() => { 
    this.value = 'one'; 
} 

このラインは、Base財産、ない方法を定義して、そしてあなたは、プロパティをオーバーライドすることはできません。 Baseで定義した唯一のインスタンスメソッドはmethodExampleです。

Childには、新しい変数をlambaExampleに割り当てます。 super.lambaExample()への電話は、の方法super()にしかアクセスできないため、失敗します。プロパティへのアクセスはthisで行われます。 ChildクラスのmethodExampleが私の構文エラーとして表示されます。

Childは、上書きされたlambaExampleプロパティでsuperを呼び出すことができますが、メソッドに対してのみ呼び出すことができます。 、私はクラスのインスタンスメソッドを宣言するための一つの方法しか承知している、とあなたはその構文と一致している場合

lambdaExample =() => { 
    super.methodExample(); // Success on super.<somemethod>() 
    this.value = 'three'; 
} 

あなたが期待するようthis作品:これは動作します

class Base { 
    value: string; 

    lambdaExample() { 
    this.value = 'one'; 
    } 

    methodExample() { 
    this.value = 'two'; 
    } 
} 

class Child extends Base { 
    lambdaExample() { 
    super.lambdaExample(); 
    this.value = 'three'; 
    } 

    methodExample() { 
    super.methodExample(); 
    this.value = 'four'; 
    } 
} 
+0

最後の文まであなたの投稿全体を追跡することができます:質問で説明したように、メソッドの例で 'this'が期待通りに機能しません。その場合、 'super'呼び出しは動作しますが、' this.value'参照は 'undefined'です。 – Jorn

+0

@Jorn - 'lambdaExample'または' methodExample'が呼び出されたときにのみ行われる値に設定するまでは、常に未定義です。 –

1

私は、回避策を見つけたが、それは醜いです:

class Base { 
    someFunction =() => { 
    this.otherFunction(); 
    } 
    protected otherFunction =() => { 
    // actual implementation here 
    } 
} 
class Child { 
    someFunction =() => { 
    this.otherFunction(); 
    // additional implementation here 
    } 
} 

このように、あなたはどのインスタンスでsomeFunctionを呼び出し、まだを使用して、元の実装にアクセスすることができます。

+0

なぜdownvote?私はすでにそれが醜いと言ったが、これまでのところ、それは唯一の解決策でもある。 – Jorn

+1

スタッカーの中には、あなた自身の疑問に答えることにかなり厄介なものがある。私はこれが良い自己回答だと思うが、誰かが例外を犯したかもしれない。 –

+0

まあ、それは私がはるかに良い[代替](http://stackoverflow.com/a/36918290/2788872)を見つけたと信じても、私ではありませんでした。 –

2

thisのスコープの問題は非常に単純なclassデコレータで取り組むことができません、あなたは、もはや方法のために醜い*矢印関数の構文を使用する必要があります - または二度と問題をスコープについて考える:

function BindMethods(target: any): any { 
    var originalCtor = target; 
    var newCtor: any = function (...args) { 
     var c: any = function() { 
      // Methods are defined on prototype. 
      var prototype = Object.getPrototypeOf(this); 

      // Bind methods. 
      Object.keys(prototype).forEach(propertyKey => { 
       if (typeof this[propertyKey] === "function") { 
        prototype[propertyKey] = this[propertyKey].bind(this); 
       } 
      }); 

      // Invoke original constructor. 
      return originalCtor.apply(this, args); 
     } 
     c.prototype = originalCtor.prototype; 
     return new c(); 
    } 

    // Copy prototype so 'intanceof' still works. 
    newCtor.prototype = originalCtor.prototype; 

    // Overrides original constructor. 
    return newCtor; 
} 
それはクラスの上にスナップと同じくらい簡単で使用

は(methodExample方法はデモンストレーション目的のみのために変更された):これはthisへの参照を保証する

@BindMethods 
class Base { 
    value: string; 

    methodExample() { 
     console.log(this.value); 
    } 
} 

I (でも継承を有する)は常に正しいS:

var base = new Base(); 
base.value = "two"; 
base.methodExample(); // "two" 
setTimeout(base.methodExample, 20); // "two" 

残念なことに、方法一つずつインスタンス参照が必要とされるように、方法のデコレータを使用して結合する方法はありません。それが必要な場合は、decorator factoryを使用してバインドするメソッドのプロパティキーを渡すことができます。


*醜い方法のために使用された場合。

関連する問題