类和多态
类
对于传统的 JavaScript 程序我们会使用函数
和基于原型的继承
来创建可重用的组件,但对于熟悉使用面向对象方式的程序员使用这些语法就有些棘手,因为他们用的是基于类的继承
并且对象是由类构建出来的。 从 ECMAScript 2015,也就是 ES6 开始, JavaScript 程序员将能够使用基于类的面向对象的方式。 使用 TypeScript,我们允许开发者现在就使用这些特性,并且编译后的 JavaScript 可以在所有主流浏览器和平台上运行,而不需要等到下个 JavaScript 版本。
基本示例
下面看一个使用类的例子:
/*
类的基本定义与使用
*/
class Person {
//声明属性
// 注意: 在ts中,类中要声明属性,必须要提前声明
name:string
age:number
//构造方法
constructor(name,age){
this.name = name
this.age = age
}
//一般方法
speak():void{
console.log(`我的名字是${this.name},我的年龄是${this.age}`)
}
}
//创建类的实例
const person1 = new Person('tom',19)
//调用实例的方法
person1.speak()
如果你使用过 C# 或 Java,你会对这种语法非常熟悉。 我们声明一个 Person
类。这个类有 4个成员:一个叫做 name
的属性,一个叫做 age
的属性,一个构造函数和一个 speak
方法。
你会注意到,我们在引用任何一个类成员的时候都用了 this
。 它表示我们访问的是类的成员。
后面一行,我们使用 new
构造了 Person
类的一个实例。它会调用之前定义的构造函数,创建一个 Person
类型的新对象,并执行构造函数初始化它。
最后一行通过 person1
对象调用其 speak
方法
继承
在 TypeScript 里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
看下面的例子:
class Animal {
run (distance: number) {
console.log(`动物奔跑了${distance}米`)
}
}
class Dog extends Animal {
cry () {
console.log('汪汪汪!')
}
}
const dog = new Dog()
dog.cry()
dog.run(100) // 可以调用从父中继承得到的方法
这个例子展示了最基本的继承:类从基类中继承了属性和方法。 这里,Dog
是一个 派生类,它派生自 Animal
基类,通过 extends
关键字。 派生类通常被称作子类,基类通常被称作超类。
因为 Dog
继承了 Animal
的功能,因此我们可以创建一个 Dog
的实例,它能够 cry()
和 run()
。
多态
多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的,
简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针
下面我们来看个更加复杂的例子:
//定义Animal基类
class Animal {
//声明属性
name:string
//构造方法
constructor(name){
this.name = name
}
//一般方法
run (distance: number) {
console.log(`动物前进了 ${distance}m`)
}
}
class Snake extends Animal{
//构造方法
constructor(name){
super(name)
}
//重写从父类继承过来的方法
run(distance:number){
console.log(`蛇前进了${distance}米`)
}
}
class Horse extends Animal{
//构造方法
constructor(name){
super(name)
}
//重写从父类继承过来的方法
run(distance:number){
console.log(`马奔跑了${distance}米`)
}
//自己的一般方法
cry(){
console.log('hou~hou~')
}
}
// 父类型引用指向子类型的实例 ==> 多态
let tom:Animal //表示tom这个变量的值,应该是animal实例
tom = new Animal('动物')
tom = new Snake('蟒蛇')
tom.run(100)
tom = new Horse('短腿马')
tom.run(300)
这个例子展示了一些上面没有提到的特性。 这一次,我们使用 extends
关键字创建了 Animal的两个子类:Horse
和 Snake
。
与前一个例子的不同点是,派生类包含了一个构造函数,它 必须调用 super()
,它会执行基类的构造函数。 而且,在构造函数里访问 this
的属性之前,我们 一定要调用 super()
。 这个是 TypeScript 强制执行的一条重要规则。
这个例子演示了如何在子类里可以重写父类的方法。Snake
类和 Horse
类都创建了 run
方法,它们重写了从 Animal
继承来的 run
方法,使得 run
方法根据不同的类而具有不同的功能。注意,即使 tom
被声明为 Animal
类型,但因为它的值是 Horse
,调用 tom.run(34)
时,它会调用 Horse
里重写的方法。