TypeScript中的“扩展”和“实现”之间有什么区别


Answers:


153

精简版

  • extends 手段:

新类是孩子。它从继承中获得收益。它具有所有属性,方法作为其父级。它可以覆盖其中一些并实现新功能,但已经包含了父级内容。

  • implements 手段:

新类可视为同一“形”,而这是不是一个孩子。可以将其传递给需要的任何方法Person,而不管其父对象是否不同。Person

更多 ...

OOP (C#,Java等语言)中,我们将使用

extends从继承中获利(请参阅wiki)。小引用:

...在大多数基于类的面向对象的语言中,继承是一种机制,其中一个对象获取父对象的所有属性和行为。继承使程序员能够:创建在现有类之上构建的类...

implements多态性将更多(请参阅wiki)。小引用:

...多态性是为不同类型的实体提供单一接口的方法...

因此,我们可以拥有真正不同的继承树class Man

class Man extends Human ...

但是如果我们也声明可以假装为其他类型- Person

class Man extends Human 
          implements Person ...

..那么我们可以在Person需要的任何地方使用它。我们只需要履行Persons的职责即可"interface" (即实施所有公共物品)

implement其他班?那真的是很酷的东西

Javascript的漂亮面孔(好处之一)是Duck键入的内置支持(请参阅wiki)。小引用:

“如果它走路像鸭子,却像鸭子一样嘎嘎叫,那它一定是鸭子。”

因此,在Javascript中,如果两个不同的对象具有相同的方法(例如render()),则可以将它们传递给期望它的函数:

function(engine){
  engine.render() // any type implementing render() can be passed
}

为了不失这一点-我们可以在Typescript中做同样的事情-带有更多类型的支持。那就是那里

class implements class

在有意义的地方发挥作用

在OOP语言中C#...无法做到这一点...

此外,文档应在此处提供帮助:

接口扩展类

接口类型扩展类类型时,它将继承该类的成员,但不继承其实现。好像该接口声明了该类的所有成员而没有提供实现。接口甚至继承基类的私有成员和受保护成员。这意味着,当您创建一个扩展带有私有成员或受保护成员的类的接口时,该接口类型只能由该类或其子类实现。

当您具有较大的继承层次结构,但要指定您的代码仅适用于具有某些属性的子类时,这很有用。子类除了从基类继承外不必关联。例如:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    private state: any;
    select() { }
}

class Location {

}

所以,虽然

  • extends 意味着-它从其父获得所有
  • implements在这种情况下,几乎就像实现接口一样。子对象可以假装它是父对象...但是它没有任何实现

当您说“ extends-它从其父级获得全部收益”时,它适用于私人成员吗?举例来说class Person {private name: string} class man extends Person{gender: string;}确实man具有属性的名称?
davejoem '16

那里也有私人的。TS不能访问。保护它们,您就可以使用它们。在“实施”的情况下,只有公共部分才有意义。希望能
有所

极好的答案。只是不确定您的评论“私有在那里,但TS无法访问”。您是说在新创建的子对象中复制了私有属性吗?对于工具而言,仅复制公共属性?
kushalvm

另外,我还提出了一个观点。如果这是extends的定义。那么请你能不能解释一下这个stackoverflow.com/questions/60390454/...
kushalvm

98

在打字稿(和其他一些OO语言)中,您具有类和接口。

接口没有实现,只是该类型的成员/方法的“合同”。
例如:

interface Point {
    x: number;
    y: number;
    distance(other: Point): number;
}

实现此Point接口的实例必须具有两个类型为number的成员:xy,以及一个distance接收另一个Point实例并返回的方法number
该接口没有实现任何这些。

类是实现:

class PointImplementation implements Point {
    public x: number;
    public y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    public distance(other: Point): number {
        return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
    }
}

操场上的代码

在示例中,Person扩展类时将其视为类,实现时将其视为接口。
您的代码:

class Person {
    name: string;
    age: number;
}
class Child  extends Person {}

class Man implements Person {}

出现编译错误:

“ Man”类错误地实现了“ Person”接口。
类型“ Man”中缺少属性“名称”。

那是因为接口缺乏实现。
因此,如果您implement是一个班级,那么您仅需执行其“合同”而不执行该实现,因此您需要这样做:

class NoErrorMan implements Person {
    name: string;
    age: number;
}

操场上的代码

最重要的是,在大多数情况下,您想要extend另一个类而不是另一个类implement


7
这个答案更容易理解。
Akshay Raut

6

来自@ nitzan-tomer的好答案!对我有很大帮助...我通过以下方式扩展了他的演示:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

以及它们在期望IPoint类型的函数中的行为。

因此,到目前为止,我已经学到了什么,并且一直用作经验法则​​:如果您正在使用期望泛型的类和方法,请使用接口作为期望的类型。并确保父类或基类使用该接口。这样,您就可以使用那些实现接口的子类中的所有子类。

这是扩展的演示


这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论。- 评分
aronisstav

1
@aronisstav我只发布了一个扩展演示,内容是我找到了一个已经对我有所帮助的好答案。但是也许其他人会发现我所做的扩展演示的工作很有用。就这样。注释并不是真正用来放置代码块的,因此这就是为什么我在Answer-Post中发现它更好理解的原因。那么这是什么问题呢?
andzep

由于长度和内容的原因,您的答案被(自动?)标记了,并出现在我的审阅队列中,我对标记中提出的原因表示赞赏。它的主要贡献(解释您扩展了此演示)可能会更好。加上这一段,也许确实更有用。
aronisstav

@andzep您的扩展演示示例非常有用。
Namit

3
  1. 接口扩展了形状的接口
  2. 界面扩展了类的形状
  3. 类实现接口应实现该接口提供的所有字段
  4. 类以形状实现类
  5. 类扩展了所有字段的类

extends着重于继承,并implements着重于约束是接口还是类。


0

扩展VS工具

  • extends:子类(已扩展)将继承该类的所有属性和方法
  • implements:使用implements关键字的类将需要实现该类的所有属性和方法implements

简单来说:

  • extends:在这里,您可以从父类获得所有这些方法/属性,因此您不必自己实现
  • implements:这是全班必须遵守的合同。这个类必须实现至少下列方法/属性

例:

class Person {
  name: string;
  age: number;

  walk(): void {
    console.log('Walking (person Class)')
  }

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class child extends Person { }

// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
  name: string;
  age: number

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  walk(): void {
    console.log('Walking (man class)')
  }

}

(new child('Mike', 12)).walk();
// logs: Walking(person Class)

(new man('Tom', 12)).walk();
// logs: Walking(man class)

在该示例中,我们可以观察到子类继承了Person的所有内容,而man类必须继承了Person本身的所有内容。

如果要从man类中删除某些内容(例如walk方法),则会得到以下编译时错误:

“ man”类错误地实现了“ Person”类。您是要扩展“人员”并将其成员继承为子类吗?“ man”类型缺少属性“ walk”,但在“ Person”类型中是必需的。(2720)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.