从父级调用时的Typescript子类范围问题

时间:2018-04-15 13:05:08

标签: typescript scope subclass

我整夜都在用这个问题拉我的头发所以我建立了一个简单的(也许不那么简单)的例子。 问题是:

  1. 我创建了一个抽象类,我称之为Father
  2. 在构造函数中,我调用了一个抽象方法call load()
  3. 我扩展了一个名为Child的儿童课。
  4. 在那个子类中,我定义了一个名为_childExtraData的属性,该属性不在其父类中。
  5. 在子类中,我定义方法load()并尝试更改_childExtraData
  6. 在所有这些步骤中都没有给出错误,但是属性没有被修改,任何线索为什么?

    我用来测试的代码如下:

    abstract class Father<T> {
        protected _fatherData: T = null;
        protected _fatherExtraData: string = null;
    
        constructor(data: T) {
            this._fatherData = data;
    
            this.load();
        }
    
        public fatherData(): T {
            return this._fatherData;
        }
        public fatherExtraData(): string {
            return this._fatherExtraData;
        }
    
        protected abstract load(): void;
    }
    
    class Child extends Father<string> {
        protected _childData: string = null;
        protected _childExtraData: string = null;
    
        constructor(fatherData: string) {
            super(fatherData);
        }
    
        public childData(): string {
            return this._childData;
        }
        public childExtraData(): string {
            return this._childExtraData;
        }
        public setChildData(data: string): void {
            this._childData = data;
        }
    
        protected load(): void {
            this._fatherExtraData = 'father extra';
            this._childExtraData = 'child extra';
        }
    }
    
    const test: Child = new Child('something for the father');
    test.setChildData('something for the kid');
    
    let text: string = '';
    text += `FATHER: ${test.fatherData()}\n`;
    text += ` extra: ${test.fatherExtraData()}\n`;
    text += `CHILD:  ${test.childData()}\n`;
    text += ` extra: ${test.childExtraData()}\n`;
    document.body.innerHTML = `<pre>${text}</pre>`;
    

    从这里我期待这样的事情:

    FATHER: something for the father
     extra: father extra
    CHILD:  something for the kid
     extra: child extra
    

    但我得到了这个:

    FATHER: something for the father
     extra: father extra
    CHILD:  something for the kid
     extra: null
    

    在某种程度上,我知道调用方法load()的{​​{1}}是Father而不是Child弄乱了范围而没有按预期行事。

    注意:

    1. 抽象与否是同样的问题。
    2. 泛型与否它也是一样的。

1 个答案:

答案 0 :(得分:1)

您的Child类与以下代码等效,它应该清楚说明您观察此行为的原因:

class Child extends Father<string> {
  protected _childData: string;
  protected _childExtraData: string;

  constructor(fatherData: string) {
    super(fatherData);

    console.log('in constructor: ' + this._childExtraData);

    this._childData = null;
    this._childExtraData = null;
  }

  public childData(): string {
    return this._childData;
  }
  public childExtraData(): string {
    return this._childExtraData;
  }
  public setChildData(data: string): void {
    this._childData = data;
  }

  protected load(): void {
    this._fatherExtraData = 'father extra';
    this._childExtraData = 'child extra';
  }
}

简而言之:在超级构造函数初始化之后,子构造函数将字段重置为null。

从基本cass构造函数调用一个可覆盖的方法是一个坏主意:子方法将在一个尚未被其构造函数初始化的对象上调用,从而导致各种微妙的错误,例如你的#39 ;看到那里。避免这种不良做法。