2

从打字稿手册中阅读示例:

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是 aAnimal具有 a 的属性Horse。是对的吗?

  • 这样做有什么意义?不声明为var tom: Horse = ...

  • 只有一个版本让他有机会降级/更改/进化到一个Snake或任何其他Animal. 我对吗?

  • ...或者也许这只是一个错字?

4

1 回答 1

3

在上面的示例中,Animal是 和 的超类(也称为基类Horse类)Snake。相应地,HorseSnake是 的子类派生类Animal

当您声明子类时:

class Snake extends Animal
...
class Horse extends Animal

您是在告诉编译器,any every Snakeand everyHorse实际上也是 an Animal。这使得Animal该程序的“世界”类别更加广泛。Snake并将继承的属性,但他们可以Horse将它们(和/或添加一些自己的)更改为更专业Animal

  • tom的声明告诉编译器该变量将接受任何Animal. 正如我们之前看到的, aHorse是 an Animal,所以编译器让它通过。

  • 因此,他们说明了这样一个事实,即无论何时在任何表达式中都需要超类的成员,它的任何子类的一个成员都是可以接受的。这称为协方差

  • 从最字面意义上说,没有进化或退化。线

    tom: Animal = new Horse("Tommy the Palomino");

    首先导致创建一个新Horse对象。然后将对象分配给变量tom,但此分配不会更改对象的属性。如果您运行该示例,您会看到该调用horse.move()实际上调用了Horse方法的版本move,它会报告“Tommy the Palomino 移动了 45m”。

    Horse将 a 赋值给 an唯一明显的副作用Animal是,作为最通用类型的变量不知道Horse. 它只知道所有Animals 的共同点。假设是这样Horse声明的:

    class Horse extends Animal {
        constructor(name: string) { super(name); }
        move(meters = 45) {
            //...
        }
        swat_fly() { /* ... */ }
    }
    

    你就不能打电话了tom.swat_fly()。如果您愿意,您要么需要进行类型转换tom(像这样:),要么将(<Horse>tom).swat_fly()其声明为 aHorse而不是Animal. 但我重申:对象的属性不会更改为超类的。

  • 所以不,这不是错字:)

于 2015-08-26T18:10:06.760 回答