从typescript manual阅读示例:
class Animal {
name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number = 0) {
alert(this.name + " moved " + meters + "m.");
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(meters = 5) {
alert("Slithering...");
super.move(meters);
}
}
class Horse extends Animal {
constructor(name: string) { super(name); }
move(meters = 45) {
alert("Galloping...");
super.move(meters);
}
}
var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
问题在于var tom: Animal = new Horse("Tommy the Palomino");
行:
据我所知,tom
是一个Animal
,其属性为Horse
。是对的吗?
这样做有什么意义?不要声明为var tom: Horse = ...
?
只有一个版本可以让他有机会降级/更改/演变为Snake
或任何其他Animal
。我是对的吗?
......或许这只是一个错字?
答案 0 :(得分:3)
在上面的示例中,Animal
是{{>>超类(也称为基类或父类)Horse
1}}和Snake
。相应地,Horse
和Snake
是Animal
的子类(派生类)。
声明子类时:
class Snake extends Animal
...
class Horse extends Animal
您告诉编译器,每个Snake
和每个Horse
实际上都是Animal
。这使Animal
成为" world"中更广泛的类别。该计划。 Snake
和Horse
将继承 Animal
的属性,但他们可以更改它们(和/或添加一些自己的属性)以更多专门
tom
的声明告诉编译器该变量将接受任何Animal
。正如我们之前看到的,Horse
是Animal
,因此编译器允许它通过。
因此,它们说明了这样一个事实:每当任何表达式中需要超类的成员时,任何子类的一个成员都是可接受的。这称为协方差。
从字面意义上讲,没有进化或转变。这条线
tom: Animal = new Horse("Tommy the Palomino");
首先导致创建一个新的Horse
对象。然后将该对象分配给变量tom
,但此赋值确实不更改对象的属性。如果您运行该示例,则会发现调用horse.move()
实际上调用了方法Horse
的{{1}}版本,该版本会报告" Palmyino移动的Tommy 45米"
将move
分配给Horse
的唯一明显的副作用是,最常见类型的变量不会知道{{1}的任何特定属性}。它只知道所有Animal
的共同点。让我们说Horse
就像这样声明:
Animal
您无法拨打Horse
。如果您愿意,您需要对class Horse extends Animal {
constructor(name: string) { super(name); }
move(meters = 45) {
//...
}
swat_fly() { /* ... */ }
}
进行类型转换(例如:tom.swat_fly()
)或将其声明为tom
而不是(<Horse>tom).swat_fly()
。但我重申:对象的属性不会更改为超类。
所以不,它不是一个错字:)