类
- 引用类的成员时,需要加
this - 我们使用 new 构造了 Greeter 类的一个实例。 它会调用之前定义的构造函数,创建一个 Greeter 类型的新对象,并执行构造函数初始化它。 示例:
class Greeter {
//属性
greeting: string
//构造函数
constructor(message: string) {
this.greeting = message
}
//方法
greet() {
return "Hello," + this.greeting
}
}
let greeter = new Greeter("world")
简单的继承示例:
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}米`)
}
}
class Dog extends Animal {
bark() {
console.log("wang!wang!")
}
}
const dog = new Dog()
dog.bark()
dog.move(10)
复杂一点得继承示例:
class Animal {
name: string
constructor(theName: string) {
this.name = theName
}
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}米`)
}
}
class Snake extends Animal {
// 子类包含一个构造函数,必须调用 super(),它会执行基类的构造函数。在构函数访问this的属性之前,一定要调用super()。这是TypeScript强制执行的一条重要规则。
constructor(name: string) {
super(name)
}
move(distanceInMeters = 45) {
console.log("蛇...")
super.move(distanceInMeters) //访问类属性前,需调用super,这里重写了从基类继承来的move方法,使得具有不同的功能
}
}
class Horse extends Animal {
constructor(name: string) {
super(name)
}
move(distanceInMeters: number = 35) {
console.log("马...")
super.move(distanceInMeters)
}
}
let sam = new Snake("sammy the Python")
let tom: Animal = new Horse("Tommy the Palomino")
sam.move()
tom.move(34) //这里tom声明使Animal类型,但是值为Horse,调用tom.move时,会调用Horse里重写的方法
//输出:
// 蛇...
// Sammy the Python moved 5m.
// 马...
// Tommy the Palomino moved 34m.
静态属性
创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。
static定义静态属性,如果要访问静态属性的话,前面必须加上类名(与访问实例属性上加this一样)
class Grid {
static orgin = { x: 0, y: 0 } // static定义orgin这个静态属性
abc:(point:{x:number,y:number}){
//这里访问静态属性时,在属性前加上类名的前缀
let xDist = (point.x - Grid.origin.x)
let yDist = (point.y - Grid.origin.y)
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale
}
constructor(public scale: number) //这里构造函数里面是定义的实例参数,用到实例属性的时候,前面是加 this 的前缀
}
let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale
console.log(grid1.abc({x: 10, y: 10}));
console.log(grid2.abc({x: 10, y: 10}));
抽象类
- 关键字
abstract定义抽象类和在抽象类内部定义抽象方法 - 抽象类中的方法,不包含具体实现,只能在派生类(子类)实现
- 抽象类定义方法和接口类似,只定义方法签名,不包含具体方法体
- 抽象方法必须包含 abstract 关键字并且可以包含访问修饰符
- 抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化,直接实例化会报错
abstract class A {
constructor(public name: string) {}
//普通定义方法,包括具体实现,访问实例属性用this
printName(): void {
console.log("名字:" + this.name)
}
//抽象类方法,必须有关键字 abstract ,并且不包含具体实现,只能在派生类实现
abstract printMeeting(): void
}
//作为抽象类 A 的派生类 B 登场
class B extends A {
constructor() {
//在派生类的构造函数必须调用super()
super("LALALALLALA")
}
printMeeting(): void {
console.log("这是基类A定义的抽象类方法,在派生类B的实现")
}
hello(): void {
console.log("这是没有在基类A定义的方法,只是派生类B定义的普通方法")
}
}
let a: A // 允许创建一个抽象类型的引用
a = new A() //报错!不能创建一个抽象类的实例,直接实例化报错
a = new B() // 允许对一个抽象子类进行实例化和赋值
a.printName() //这是抽象类 A里面定义的普通方法
a.printMeeting() //这是调用抽象类 A 里面定义的抽象类方法
a.hello() //报错! 这个方法抽象类A中并没有定义,所以引用报错
高级技巧
构造函数
class Greeter {
greeting: string
constructor(message: string) {
this.greeting = message
}
greet() {
return "hello," + this.greeting
}
}
let greeter: Greeter //这样写是表明Greeter类的实例的类型是 Greeter
greeter = new Greeter("world")
console.log(greeter.greet())
把类当做接口使用
类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。(有点不明白 = =)
class Point {
x: number
y: number
}
interface Point3d extends Point {
z: number
}
let point3d: Point3d = { x: 1, y: 2, z: 3 }