OOP 常见的两种实现方式: class-based 和 prototype-based
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
Inheritance
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
console.log("Galloping...");
super.move(distanceInMeters);
}
}
let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
public
, private
, and protected
modifiers
public 是默认的
Understanding private
TypeScript is a structural type system. When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible
然而, 如果用 private 或者 protected 来修饰就有点不同了:
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
animal = rhino;
animal = employee; // Error: 'Animal' and 'Employee' are not compatible
因为:
Animal and Rhino share the private side of their shape from the same declaration of private name: string in Animal, they are compatible
Even though Employee also has a private member called name, it’s not the one we declared in Animal
Understanding protected
和 private 差不多, 只是能在子类里使用父类的 protected
还有一个很有趣的点就是把 protected 用在父类的 constructor 上
class Person {
protected name: string;
// 这样就不能直接 new Person() 了, 只能用来当父类进行继承
protected constructor(theName: string) { this.name = theName; }
}
// Employee can extend Person
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected
readonly
modifier
readonly 的属性只能在声明的时候或者在构造函数里赋值
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
Parameter properties
有种简写方式, 能让属性声明再在构造函数里赋值这两部操作合成一步:
// 就是直接在构造函数的参数里加上对应的修饰符
// 同理, 把 readonly 换成 public, protected, private 都是一样的
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {
}
}
Accessors
就是 getter 和 setter
只带 getter 不带 setter 的属性默认会标记为 readonly 的
Static Properties
加 static 关键字
Abstract Classes
抽象类用作基类
和 interface 不同的是, 它可以包含方法的实现细节
抽象方法不包含具体实现, 并且必须在子类实现
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}