我整夜都在用这个问题拉我的头发所以我建立了一个简单的(也许不那么简单)的例子。 问题是:
Father
。load()
Child
的儿童课。_childExtraData
的属性,该属性不在其父类中。load()
并尝试更改_childExtraData
。在所有这些步骤中都没有给出错误,但是属性没有被修改,任何线索为什么?
我用来测试的代码如下:
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
弄乱了范围而没有按预期行事。
注意:
答案 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 ;看到那里。避免这种不良做法。