JavaScript程序使用函数和基于原型的继承来创建可重用的组件。这对于熟练使用面向对象方式的程序员来讲就有些棘手了,因为他们用的是基于类的继承,并且对象是由类构建出来的。
TypeScript提供了强大的类型,并能够支持完善的面向对象体系。如果读者有其他语言(如Java、ActionScript等)的面向对象编程经验,那理解TypeScript的面向对象体系就非常容易了。
1. 类的定义与使用
使用关键字“class”来定义类。下面是一个例子。
在该例子中定义了一个名为“Greeter”的类。该类具有属性greeting、构造函数constructor()、方法greet()等成员。
你可能注意到,在引用任何一个类成员时都使用了this,它表示访问的是类的成员。
通过关键字“new”能够初始化Greeter类的一个实例,并使用实例的greet()方法来输出欢迎信息。以下是控制台输出内容:
2. 继承
类可以被继承。来看下面的例子。
Animal代表了动物的基类。Snake(蛇)和Horse(马)都属于动物,因此它们都可以继承Animal类,具备动物的一般特征。在本例中,动物的一般特征是都有自己的名字,并且能够移动(move)。
通过new Snake和new Horse分别实现Snake类和Horse类的实例化,并让每个实例拥有各自不同的move()方法。
3.public 、 private 与 protected 修饰符
在上面的例子中,我们可以自由地访问程序里定义的成员。你可能注意到,在之前的代码里并没有使用public来进行修饰。
在TypeScript中,共有3种修饰符。
● public修饰符:外部可以自由访问该修饰符所标记的成员。成员默认是public类型的。
● private修饰符:当成员被标记为private时,不能在声明它的类的外部访问它。
● protected修饰符:与private修饰符的行为很相似,但有一点不同——protected成员在派生类中仍然可以被访问。
4. 静态属性
到目前为止,我们只讨论了类的实例成员——那些仅当类被实例化时才会被初始化的属性。也可以创建类的静态成员,这些属性存在于类本身,而不是类的实例上。
观察下面的例子。
在这个例子中,使用“static”关键字定义origin XXXX,因为它是所有网格都会用到的属性。每个实例想要访问这个属性,都要在origin前面加上类名。如同在实例属性上使用“this.”前缀来访问属性一样,在这里使用“Grid.”来访问静态属性。
5. 抽象类
抽象类是其他派生类的基类,它们一般不会直接被实例化。不同于接口,抽象类可以包含成员的实现细节。
关键字“abstract”用于定义抽象类,并在抽象类内部定义抽象方法。观察以下代码。
抽象类中的抽象方法不包含具体实现,并且必须在派生类中实现。抽象方法的语法与接口方法的语法相似,两者都只定义方法签名,而不包含方法体。然而,抽象方法必须包含关键字“abstract”,并且可以包含访问修饰符。以下是完整的示例。
接口就是契约,用于约定代码或第三方代码是如何被执行调用的。接口也可以通过继承来实现扩展。
1. 接口定义
接口使用关键字“interface”来定义。下面是一个定义接口的例子。
2. 接口实现
接口使用关键字“implements”来实现。下面是一个实现ClockInterface接口的例子。
3. 接口继承
接口可以通过继承来实现扩展。下面是一个接口继承的例子。
在大型软件中,不仅要创建一致的、定义良好的API,也要考虑组件的重用性。组件不仅能支持当前的数据类型,也能支持未来的数据类型。使用泛型就能创建可重用的组件。
在C#和Java这类语言中,泛型已经被广泛应用。TypeScript同样支持泛型。
下面创建一个使用泛型的例子:identity()函数。该函数会返回任何传入它的值。
1. 不用泛型的情况
如果不用泛型,则这个函数可能是下面这样的。
或者,用any类型来定义函数。
虽然使用any类型后这个函数已经能接收任何类型的arg参数,但是丢失了一些信息,即无法保证传入的参数类型与返回值的类型是相同的。因此,我们需要一种方法,使返回值的类型与传入的参数类型是相同的。
2. 采用泛型的情况
以下就是使用了泛型的例子。
给identity添加了一个类型变量T。T用于捕获用户传入的类型(如Number),然后就可以使用这个类型了。之后,再次使用T作为返回值类型。现在可以知道,参数类型与返回值类型是相同的。之所以叫作泛型,是因为它可以适用于多个类型。不同于使用any,它不会丢失类型信息。
在定义了泛型函数后,可以通过两种方式来使用。
● 传入所有的参数,包含类型参数。
在这里,我们指定了T是String类型的,并作为一个参数传递给函数。
● 利用类型推导,可以省略显式传入类型,编译器会根据传入的参数自动确定 T 的类型(这种方法更普遍)。
枚举通过关键字“enum”来定义。以下是一个枚举的示例。
一个枚举类型可以包含0个或多个枚举成员。枚举成员具有一个数字值,它可以是常量或通过计算得出的值。当满足如下条件之一时,枚举成员被当作常量。
● 不具有初始化函数,并且之前的枚举成员是常量。在这种情况下,当前枚举成员的值为上一个枚举成员的值加1。但第一个枚举成员是一个例外。如果它没有初始化函数,那么它的初始值为0。
● 枚举成员使用常量枚举表达式初始化。常量枚举表达式是TypeScript表达式的子集,它可以在编译阶段求值。
以下示例展示了枚举成员被当作通过计算得出的值。