在类型脚本中调用基类构造函数中的重写方法

当从基类构造函数调用重写的方法时,无法正确获取子类属性的值。

例如:

class A
{
constructor()
{
this.MyvirtualMethod();
}


protected MyvirtualMethod(): void
{


}
}


class B extends A
{
private testString: string = "Test String";


public MyvirtualMethod(): void
{
alert(this.testString); // This becomes undefined
}
}

我想知道如何正确地覆盖打印脚本中的函数。

138539 次浏览

The order of execution is:

  1. A's constructor
  2. B's constructor

The assignment occurs in B's constructor after A's constructor—_super—has been called:

function B() {
_super.apply(this, arguments);   // MyvirtualMethod called in here
this.testString = "Test String"; // testString assigned here
}

So the following happens:

var b = new B();     // undefined
b.MyvirtualMethod(); // "Test String"

You will need to change your code to deal with this. For example, by calling this.MyvirtualMethod() in B's constructor, by creating a factory method to create the object and then execute the function, or by passing the string into A's constructor and working that out somehow... there's lots of possibilities.

The key is calling the parent's method using super.methodName();

class A {
// A protected method
protected doStuff()
{
alert("Called from A");
}


// Expose the protected method as a public function
public callDoStuff()
{
this.doStuff();
}
}


class B extends A {


// Override the protected method
protected doStuff()
{
// If we want we can still explicitly call the initial method
super.doStuff();
alert("Called from B");
}
}


var a = new A();
a.callDoStuff(); // Will only alert "Called from A"


var b = new B()
b.callDoStuff(); // Will alert "Called from A" then "Called from B"

Try it here

If you want a super class to call a function from a subclass, the cleanest way is to define an abstract pattern, in this manner you explicitly know the method exists somewhere and must be overridden by a subclass.

This is as an example, normally you do not call a sub method within the constructor as the sub instance is not initialized yet… (reason why you have an "undefined" in your question's example)

abstract class A {
// The abstract method the subclass will have to call
protected abstract doStuff():void;


constructor(){
alert("Super class A constructed, calling now 'doStuff'")
this.doStuff();
}
}


class B extends A{


// Define here the abstract method
protected doStuff()
{
alert("Submethod called");
}
}


var b = new B();

Test it Here

And if like @Max you really want to avoid implementing the abstract method everywhere, just get rid of it. I don't recommend this approach because you might forget you are overriding the method.

abstract class A {
constructor() {
alert("Super class A constructed, calling now 'doStuff'")
this.doStuff();
}


// The fallback method the subclass will call if not overridden
protected doStuff(): void {
alert("Default doStuff");
};
}


class B extends A {
// Override doStuff()
protected doStuff() {
alert("Submethod called");
}
}


class C extends A {
// No doStuff() overriding, fallback on A.doStuff()
}


var b = new B();
var c = new C();

Try it Here

below is an generic example

    //base class
class A {
        

// The virtual method
protected virtualStuff1?():void;
    

public Stuff2(){
//Calling overridden child method by parent if implemented
this.virtualStuff1 && this.virtualStuff1();
alert("Baseclass Stuff2");
}
}
    

//class B implementing virtual method
class B extends A{
        

// overriding virtual method
public virtualStuff1()
{
alert("Class B virtualStuff1");
}
}
    

//Class C not implementing virtual method
class C extends A{
     

}
    

var b1 = new B();
var c1= new C();
b1.Stuff2();
b1.virtualStuff1();
c1.Stuff2();