基本示例

  1. class Person {
  2. name: string;
  3. age: number;
  4. constructor(name: string, age: number) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. sayHello() {
  9. console.log(this.name);
  10. }
  11. }
  12. let zs: Person = new Person('张三', 18);

构造函数

继承

  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();

这个例子展示了最基本的继承:类从基类中继承了属性和方法。 这里, Dog是一个 派生类,它派生自 Animal 基类,通过 extends关键字。 派生类通常被称作 子类,基类通常被称作 超类

因为 Dog继承了 Animal的功能,因此我们可以创建一个 Dog的实例,它能够 bark()move()

下面是一个更复杂的例子:

  1. class Animal {
  2. name: string;
  3. constructor(theName: string) { this.name = theName; }
  4. move(distanceInMeters: number = 0) {
  5. console.log(`${this.name} moved ${distanceInMeters}m.`);
  6. }
  7. }
  8. class Snake extends Animal {
  9. constructor(name: string) { super(name); }
  10. move(distanceInMeters = 5) {
  11. console.log("Slithering...");
  12. super.move(distanceInMeters);
  13. }
  14. }
  15. class Horse extends Animal {
  16. constructor(name: string) { super(name); }
  17. move(distanceInMeters = 45) {
  18. console.log("Galloping...");
  19. super.move(distanceInMeters);
  20. }
  21. }
  22. let sam = new Snake("Sammy the Python");
  23. let tom: Animal = new Horse("Tommy the Palomino");
  24. sam.move();
  25. tom.move(34);

与前一个例子的不同点是,派生类包含了一个构造函数,它 必须调用 super(),它会执行基类的构造函数。 而且,在构造函数里访问 this的属性之前,我们 一定要调用 super()。 这个是TypeScript强制执行的一条重要规则。

这个例子演示了如何在子类里可以重写父类的方法。 Snake类和 Horse类都创建了 move方法,它们重写了从Animal继承来的 move方法,使得 move方法根据不同的类而具有不同的功能。 注意,即使 tom被声明为Animal类型,但因为它的值是 Horse,调用 tom.move(34)时,它会调用 Horse里重写的方法:

  1. Slithering...
  2. Sammy the Python moved 5m.
  3. Galloping...
  4. Tommy the Palomino moved 34m.

实例成员访问修饰符

public 开放的

  • 默认为 public
  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 私有的

  • 不能被外部访问,只能在类的内部访问使用
  • 私有成员不会被继承
  1. class Person {
  2. public name: string;
  3. public age: number = 18;
  4. private type: string = 'human'
  5. public constructor (name, age) {
  6. this.name = name
  7. this.age = age
  8. }
  9. }

protected 受保护的

  • private 类似,但是可以被继承
  1. class Person {
  2. protected name: string;
  3. constructor(name: string) { this.name = name; }
  4. }
  5. class Employee extends Person {
  6. private department: string;
  7. constructor(name: string, department: string) {
  8. super(name)
  9. this.department = department;
  10. }
  11. public getElevatorPitch() {
  12. return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  13. }
  14. }
  15. let howard = new Employee("Howard", "Sales");
  16. console.log(howard.getElevatorPitch());
  17. console.log(howard.name); // 错误

注意,我们不能在 Person类外使用 name,但是我们仍然可以通过 Employee类的实例方法访问,因为Employee是由 Person派生而来的。

readonly 只读的

在参数中使用修饰符

在上面的例子中,我们不得不定义一个受保护的成员 name和一个构造函数参数 theNamePerson类里,并且立刻给 nametheName赋值。 这种情况经常会遇到。 参数属性可以方便地让我们在一个地方定义并初始化一个成员。

  1. class Person {
  2. name: string;
  3. age: number;
  4. constructor(name: string, age: number) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. }

可以简写为:

  1. class Person {
  2. constructor(public name: string, public age: number) {
  3. }
  4. }

属性的存(get)取(set)器

  1. let passcode = "secret passcode";
  2. class Employee {
  3. // 私有成员,外部无法访问
  4. private _fullName: string;
  5. // 当访问 实例.fullName 的时候会调用 get 方法
  6. get fullName(): string {
  7. return this._fullName;
  8. }
  9. // 当对 实例.fullName = xxx 赋值的时候会调用 set 方法
  10. set fullName(newName: string) {
  11. if (passcode && passcode == "secret passcode") {
  12. this._fullName = newName;
  13. }
  14. else {
  15. console.log("Error: Unauthorized update of employee!");
  16. }
  17. }
  18. }
  19. let employee = new Employee();
  20. employee.fullName = "Bob Smith";
  21. if (employee.fullName) {
  22. alert(employee.fullName);
  23. }

静态成员

  • 不需要实例化访问的成员称之为静态成员,即只能被类访问的成员
  • static 关键字
  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}));