看了codewhy的前端TS,下面是我对TS抽象类的相关知识的笔记。
下面代码作用是计算各种图形面积,通过调用makeArea()函数传入一个图形对象shape,函数内部调用每个图形对象都有的方法getArea()获取图形面积并返回,一共写了两个class用来测试。
这种写法的弊端在于makeArea()的函数的参数是any类型,这导致非图形类也可以传入,可是非图形类并没有getArea()方法。所以这种写法存在传参错误的分险:
function makeArea(shape: any) {
return shape.getArea()
}
class Rectangle{
private width: number
private height: number
constructor(width: number, height: number) {
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
class Circle{
private r: number
constructor(r: number) {
this.r = r
}
getArea() {
return this.r * this.r * 3.14
}
}
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
// 由于传入的不是图形对象,没有getArea()方法。又因为参数设置的时any,所以在编译阶段并不会报错,在运行时会报错
const oth = makeArea(12341)
现在根据上面展现出来的问题对代码进行优化。很明显上面这段代码就是各个类型约束问题,我们可以定义一个图形类的父类Shape,让所有的图形类都继承这个父类,然后对makeArea()函数的参数类型规定为Shape,这样就解决参数类型错误的问题。
function makeArea(shape: Shape) {
return shape.getArea()
}
class Shape{
getArea() {}
}
class Rectangle extends Shape{
private width: number
private height: number
constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
class Circle extends Shape{
private r: number
constructor(r: number) {
super()
this.r = r
}
getArea() {
return this.r * this.r * 3.14
}
}
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
// 将参数类型改为Shape只有下面代码在编辑的时候就会报错了
// const oth = makeArea(12341)
虽然能够避免其它类型的参数误传,但如果传的是Shape类型的对像还是会有问题const oth1 = makeArea(new Shape())。因为Shape并没有实现getArea()方法,所以这种类型也是无法获取面积的。而且这个Shape类只是作为所有图形的父类,但它并不代表任何形状,所以这个类型的getArea()方法也是实现不了的。这种情况我们应该使用abstract去修饰这个方法,一个正常的方法是必须要有实现的(实现指的就是函数体里面的内容),但是被abstract修饰之后不需要去实现,在这个对象调用这个抽象的方法时也会直接提示这是一个抽象方法。这种抽象方法是必须在抽象类中的,所以Shape这个类也必须要用abstract修饰:
function makeArea(shape: Shape) {
return shape.getArea()
}
abstract class Shape{
abstract getArea()
}
class Rectangle extends Shape{
private width: number
private height: number
constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
}
class Circle extends Shape{
private r: number
constructor(r: number) {
super()
this.r = r
}
getArea() {
return this.r * this.r * 3.14
}
}
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
// 将参数类型改为Shape只有下面代码在编辑的时候就会报错了
// const oth = makeArea(12341)
// 抽象类在这里会报错
const oth1 = makeArea(new Shape())