純粋な抽象クラス(つまり、実装のない抽象クラス)があるとします。
abstract class A {
abstract m(): void;
}
C#やJavaのように、抽象クラスをextendできます:
class B extends A {
m(): void { }
}
しかし、C#とJavaのunlikeと同様に、抽象クラスをimplementすることもできます。
class C implements A {
m(): void { }
}
クラスB
とC
はどのように振る舞いますか?なぜ一方を選択するのですか?
implementsキーワードはAクラスをインターフェイスとして扱います。つまり、CはAで定義されたすべてのメソッドを実装する必要があります、[〜#〜] a [〜#〜]に実装があるかどうかは関係ありません。また、[〜#〜] c [〜#〜]にはスーパーメソッドの呼び出しはありません。
extendsは、キーワードに期待するものと同じように動作します。抽象メソッドのみを実装する必要があり、スーパーコールは利用可能/生成されます。
抽象メソッドの場合、違いはないと思います。ただし、抽象メソッドのみのclassを使用することはめったにありません。そうする場合は、インターフェイス。
これは、生成されたコードを見ると簡単にわかります。遊び場の例を作成しました here 。
私がここに導かれたのは、自分に同じ質問をしていましたが、答えを読んでいるときに、選択がinstanceof
演算子にも影響するということでした。
抽象クラスはJSに発行される実際の値であるため、サブクラスがそれを拡張するときの実行時チェックに使用できます。
abstract class A {}
class B extends A {}
class C implements A {}
console.log(new B() instanceof A) // true
console.log(new C() instanceof A) // false
@ toskv's answer に基づいて、抽象クラスをextendにすると、super()
を呼び出す必要がありますサブクラスのコンストラクター。抽象クラスをimplementする場合、super()
を呼び出す必要はありません(ただし、で宣言されたすべてのメソッドを実装する必要があります)プライベートメソッドを含む抽象クラス)。
拡張する代わりに抽象クラスを実装すると、元のクラスの依存関係とコンストラクターを気にせずにテスト用の模擬クラスを作成する場合に便利です。
拡張の例では、実際にクラスに新しいものを追加することはありません。したがって、何も拡張されません。何も拡張しないことは有効なTypeScriptですが、この場合は「実装」の方が適切だと思われます。しかし、結局のところ、それらは同等です。