一、继承的作用
继承可以描述类与类之间的关系。
如果 A 和 B 都是类,并且可以描述为 A 是 B ,则 A 和 B 形成继承关系:
- B 是父类, A 是子类
- B 派生 A , A 继承 B
- B 是 A 的基类, A 是 B 的派生类
如果 A 继承自 B ,则 A 中自动拥有 B 中的所有成员。
export class Tank {
x: number = 0
y: number = 0
}
export class PlayerTank extends Tank {
}
const p = new PlayerTank();
console.log(p.x,p.y); // 0 0
1.成员的重写
(1)重写:子类中复用父类的成员。
- 子类成员不能改变父类的成员。
- 无论是属性还是方法,子类都可以对父类的相应成员进行重写, 但是重写时,需要保证类型的匹配。
export class Tank {
x: number = 0
y: number = 0
}
export class PlayerTank extends Tank {
x: number = 20
y: number = 20
}
const p = new PlayerTank();
console.log(p.x,p.y); // 20 20
(2)注意 this 关键字:在继承关系中, this 的指向是动态的,调用方法时,根据具体的调用者确定 this 指向。
export class Tank {
name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
name: string = '玩家坦克'
}
export class EnemyTank extends Tank {
name: string = '敌方坦克'
}
const p = new PlayerTank();
const e = new EnemyTank();
p.sayHello() // 你好,我是玩家坦克
e.sayHello() // 你好,我是敌方坦克
(3) super 关键字:在子类的方法中,可以使用 super 关键字读取父类成员。
export class Tank {
name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
name: string = '玩家坦克'
life: number = 5
test() {
super.sayHello()
}
}
const p = new PlayerTank();
p.test() // 你好,我是玩家坦克
使用 this 可以达到同样的效果,但是两者有所区别:当子类中与父类中拥有同样的方法并且被调用时,通过 this 访问的是子类中的方法,通过 super 访问的是父类中的方法。
export class Tank {
name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
name: string = '玩家坦克'
life: number = 5
sayHello() {
console.log(`啦啦啦`);
}
test() {
this.sayHello() // 啦啦啦
super.sayHello() // 你好,我是玩家坦克
}
}
const p = new PlayerTank();
p.test()
2.类型匹配
鸭子辨型法。
子类的对象,始终可以赋值给父类。面向对象中,这种现象,叫做里氏替换原则。
如果需要判断一个数据的具体子类类型,可以使用 instanceof 。
下图中,可以为对象 p 赋值父类 Tank 类型。需要注意的是,在使用时,只能使用父类 Tank 里面已有的成员。
如果想要使用子类 PlayerTank 中独有的成员,可以为对象 p 赋值 PlayerTank 类型或者不限制类型。
如果确定想要为对象赋值父类类型,又想要访问子类独有类型,可以使用 instanceof 对对象进行类型判断,之后再访问:
export class Tank {
name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
name: string = '玩家坦克'
life: number = 5
}
const p:Tank = new PlayerTank();
p.sayHello()
if (p instanceof PlayerTank) {
console.log(p.life); // 5
}
3. protected 修饰符
访问权限修饰符: private public protected
protected :受保护的成员,只能在自身或子类中访问。
编译结果中没有访问修饰符。
export class Tank {
protected name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
life: number = 5
test() {
console.log(this.name);
}
}
const p = new PlayerTank();
p.test() // 坦克
export class Tank {
protected name: string = '坦克'
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
export class PlayerTank extends Tank {
protected name: string = '玩家坦克'
life: number = 5
test() {
console.log(this.name);
}
}
const p = new PlayerTank();
p.test() // 玩家坦克
二、继承的单根性和传递性
单根性:每个类最多只能拥有一个父类。
传递性:如果 A 是 B 的父类,并且 B 是 C 的父类,则可以认为 A 也是 C 的父类。
此时, b 即拥有 EnemyTank 类的属性,也拥有 Tank 类的属性。