ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。

  1. class Greeter {
  2. greeting: string;
  3. constructor(message: string) {
  4. this.greeting = message;
  5. }
  6. greet() {
  7. return "Hello, " + this.greeting;
  8. }
  9. }
  10. let greeter = new Greeter("world");

在类里面,使用()形式和箭头函数形式定义方法是有去别的. 我们这里建议使用原型的形式定义方法.
image.png

继承

在TypeScript里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。

  1. class Animal {
  2. move(distanceInMeters: number = 0) {
  3. console.log(`Animal moved ${distanceInMeters}m.`);
  4. }
  5. }
  6. class Dog extends Animal {
  7. bark() {
  8. console.log('Woof! Woof!');
  9. }
  10. }
  11. const dog = new Dog();
  12. dog.bark();
  13. dog.move(10);
  14. dog.bark();

公共,私有与受保护的修饰符

默认为public

在上面的例子里,我们可以自由的访问程序里定义的成员。 如果你对其它语言中的类比较了解,就会注意到我们在之前的代码里并没有使用public来做修饰;例如,C#要求必须明确地使用public指定成员是可见的。 在TypeScript里,成员都默认为public。
你也可以明确的将一个成员标记成public。 我们可以用下面的方式来重写上面的Animal类:

  1. class Animal {
  2. public name: string;
  3. public constructor(theName: string) { this.name = theName; }
  4. public move(distanceInMeters: number) {
  5. console.log(`${this.name} moved ${distanceInMeters}m.`);
  6. }
  7. }

理解private

当成员被标记成private时,它就不能在声明它的类的外部访问。
即时是继承的对象,依然无法直接访问.

  1. class Animal {
  2. private name: string;
  3. constructor(theName: string) { this.name = theName; }
  4. }
  5. class Rhino extends Animal {
  6. constructor() { super("Rhino"); }
  7. say(){
  8. // 这里无法访问 父类中的 private name属性
  9. console.log('this.name:',this.name);
  10. }
  11. }
  12. new Animal("Cat").name; // 错误: 'name' 是私有的.
  13. let animal = new Animal("Goat");
  14. let rhino = new Rhino();

理解protected

protected修饰符与private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问。

  1. class Animal {
  2. protected name: string;
  3. constructor(theName: string) { this.name = theName; }
  4. }
  5. class Rhino extends Animal {
  6. constructor() { super("Rhino"); }
  7. say(){
  8. // 可以访问 父类 protected name属性
  9. console.log('this.name:',this.name);
  10. }
  11. }
  12. new Animal("Cat").name; // 错误: 'name' 是私有的.
  13. let animal = new Animal("Goat");
  14. let rhino = new Rhino();

readonly修饰符

你可以使用readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

  1. class Octopus {
  2. readonly name: string;
  3. readonly numberOfLegs: number = 8;
  4. constructor (theName: string) {
  5. this.name = theName;
  6. }
  7. }
  8. let dad = new Octopus("Man with the 8 strong legs");
  9. dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

存取器

暂不处理.

静态属性

类的静态成员,这些属性存在于类本身上面而不是类的实例上。

  1. class Grid {
  2. static origin = {x: 0, y: 0};
  3. calculateDistanceFromOrigin(point: {x: number; y: number;}) {
  4. let xDist = (point.x - Grid.origin.x);
  5. let yDist = (point.y - Grid.origin.y);
  6. return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  7. }
  8. constructor (public scale: number) { }
  9. }
  10. let grid1 = new Grid(1.0); // 1x scale
  11. let grid2 = new Grid(5.0); // 5x scale
  12. console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
  13. console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

抽象类

暂不处理.

把类当做接口使用

类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。

  1. class Point {
  2. x: number;
  3. y: number;
  4. }
  5. interface Point3d extends Point {
  6. z: number;
  7. }
  8. let point3d: Point3d = {x: 1, y: 2, z: 3};