繁体   English   中英

为什么在TypeScript中公共成员可以覆盖受保护的成员?

[英]Why protected members can be overridden by public members in TypeScript?

我是Typescript的新手,所以我尝试在这个操场上玩TypeScript。 我注意到在TypeScript中,公共成员可以覆盖基类中的受保护成员:

class Base {
    protected name: string = '!'
}

class Derived extends Base{
    public name: string = '?'
}

一方面,这对我来说很有意义,因为《里斯科夫替代原则》仍然成立:基类比派生类有更严格的要求。 但是另一方面,我注意到私有成员不能被受保护的成员或公共成员所取代,这似乎与我不一致:

class Base {
    private name: string = '!'
}

class Derived extends Base{
    public name: string = '?'  // ERROR!
}

因此,我想知道:

  1. 我的观察是预期的行为还是Typescript中的错误?

  2. 如果是故意的,为什么存在这种不一致? 为什么TypeScript不要求所有重写成员具有与基类中的成员相同的可访问性? 还是允许所有具有较高可访问性的派生成员覆盖基类中的成员?

这是预期的行为。

您可以public一个protected字段,因为protected允许派生类读取和写入一个字段。 派生类可以选择使用其读取和写入字段的能力,以允许其他人读取和写入字段。 没有必要让您编写如下内容:

class Foo {
  protected someField;
}

class Bar extends Foo {
  public get someFieldButPublic() {
    return this.someField;
  }
  public set someFieldButPublic(value) {
    this.someField = value;
  }
}

如果您想要做的就是将someField公开。

您无法将private字段设为protectedpublic因为您没有对该字段的读写权限。 它是private 如果基类希望您可以访问该字段,那么他们毕竟会将其设置为protected

javascript没有此功能,因为它在java中称为字段重写。让我们看一下Java中的代码段:

class Base {
    protected String name = "!";

    public String bar() {
        return name;
    }
}

class Derived extends Base {
    public String name = "?";

    public String foo() {
        return name;
    }
}

当您持有一种派生实例时, it在Java中。 然后it.foo()返回"?" 并且it.bar()返回"!" 。但是为什么两个方法都返回"?" 在javascript中,由于javascript行为在运行时发生,并将this类型绑定到Base中的Derived,所以您无法重写javascript中的字段。还记得Function.prototype.call(thisArg)吗?在Derived类中做了类似的事情,如果您在Derived实例上调用bar方法,则实际上会将Derived类型绑定到Base类。 您可以禁止这样做,就是在Base中将字段设为私有,然后让编译器仅在打字稿中告诉您该错误。

这是预期的行为。

TypeScript编译为JavaScript。 因此,在代码中使用访问修饰符对输出绝对没有影响。 访问修饰符唯一要做的就是,如果您使用了不应访问的内容,则让编译器对您大吼大叫。

示例:这两个类都编译为完全相同的代码。 游乐场 (忽略班级名称)

// prop is private
class Test {
    private prop: string;
    constructor() {
        this.prop = "str"
    }
}

// prop is public
class Test {
    public prop: string;
    constructor() {
        this.prop = "str"
    }
}

在C#这样的语言中,私有属性是真正的私有属性,因此可以在公开name属性的同时从具有private name属性的类继承。 访问this.name继承方法将访问基类中的name属性,而访问this.name的类中的方法将使用继承类中的属性。

让我们来看一下示例中发出的JavaScript。

var __extends; // omitted for brevity
var Base = (function () {
    function Base() {
        this.name = '!';
    }
    return Base;
}());
var Derived = (function (_super) {
    __extends(Derived, _super);
    function Derived() {
        var _this = _super.apply(this, arguments) || this;
        _this.name = '?';
        return _this;
    }
    return Derived;
}(Base));

如您所见,这里发生的是Base类分配! this.name ,然后DerivedBase的假定私有name属性更改为? 显然,当Base类中的方法引用this.name并获取Derived类分配的意外值时,这可能会导致一些令人困惑的错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM