【问题标题】:Accessing overwritten protected member in extended class访问扩展类中被覆盖的受保护成员
【发布时间】:2018-03-08 23:05:49
【问题描述】:

假设我有一个Base 类和一个从Base 扩展的Test 类。 Base 类有一个受保护的成员,假设它是一个存储字符串字典的对象。我希望在Test 类中覆盖该字典,但不知何故,它无法按预期工作(至少在我的生产代码中,以及当我在JS Bin 上测试它时):

type ConstantsDict = { [key: string]: string }

abstract class Base {

    protected readonly _constants: ConstantsDict = {
        FOO: 'bar'
    }

    protected get _magicStringFoo(): string {
        return `Base: ${this._constants.FOO}`;
    }

    constructor() {
        // The magic constant FOO is incorrect when invoked in Test
        alert(this._magicStringFoo);
    }
}

class Test extends Base {
    // Overwrite inherited  member
    protected readonly _constants = {
        FOO: 'lorem ipsum dolor sit amet'
    }

    // Overwrite inherited getter
    protected get _magicStringFoo(): string {
        return `Test: ${this._constants.FOO}`;
    }

    // Let's give Test it's own getter for the same magic constant
    private get _magicStringFooPrivate(): string {
        return `Test: ${this._constants.FOO}`;
    }

    constructor() {
        super();

        // The magic constant FOO is correct over here
        alert(`Local magic constant FOO is: ${this._magicStringFooPrivate}`)
    }
}

new Test();

代码将提醒Test: bar 而不是Test: lorem ipsum dolor sit amet。好消息是,从 Base 类继承的受保护 getter 正在被 Test 覆盖,但不知何故,this 引用仍然指向不正确的类。

【问题讨论】:

  • 你已经合并了原型继承。当这段代码被转译成 javascript 时,原型链的构造就好像它是用 JavaScript 编写的一样。尽管这看起来与 Java 或 C# 相似,但底层语言并不是这样工作的。请调查原型继承。

标签: typescript


【解决方案1】:

这是由构造函数交互方式引起的排序问题。

以下是基于您的代码的构造函数(为便于使用,已删除所有其他代码)。

当你实例化一个新的Test 时,我已经在每一行注释了什么时候被调用

// 3
function Base() { 
    // 4
    this._constants = { 
        // 5
        FOO: 'bar' 
    // 6
    }; 
    // 7 (at this point, FOO is 'bar')
    alert(this._magicStringFoo);
}

// 1
function Test() { 
    // 2
    var _this = _super.call(this) || this; // <-- GO TO SUPER CLASS CONSTRUCTOR
    // 8
    _this._constants = {
        // 9
        FOO: 'lorem ipsum dolor sit amet'
    // 10
    };
    // 11
    alert("Local magic constant FOO is: " + _this._magicStringFooPrivate);
    //12
    return _this;
}

您可以在这里看到为什么子类似乎具有错误的值 - 它只是当时没有机会覆盖基类的值。

修复

我推荐的解决方法是将值传递给超类构造函数。

这是一个简单的版本:

type ConstantsDict = { [key: string]: string }

abstract class Base {
    constructor(protected magicStringFoo: string) {
        // The magic constant FOO is incorrect when invoked in Test
        alert(this.magicStringFoo);
    }
}

class Test extends Base {
    constructor() {
        super('Test: lorem ipsum dolor sit amet');
    }
}

new Test();

我已经通过了那里的测试字符串,但是您可以通过 FOO 常量或您需要的任何内容。这解决了任何订购问题。

【讨论】:

  • 如果是这种情况,是否有解决方法?
  • 没有。这个问题源于对原型继承如何工作的基本误解。原型链并没有因为您迫切希望它像 C# 或 Java 一样工作而改变。
  • 嗨@Terry - 我已经添加了我推荐的修复。还有其他可能性,比如工厂方法或时间耦合......但构造函数询问“他们需要什么”通常是最好的答案。
猜你喜欢
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 2017-08-01
  • 2016-10-01
  • 2018-11-27
相关资源
最近更新 更多