类的继承和成员修饰符
private:为私有属性,只能在当前类中访问,如果 private constructor则该类不能被实例化,不能被继承.
protected:受保护的属性,只能在当前类及其子类中访问,如果protected constructor则该类不能被实例化,但是可以被继承public:默认为public,公用属性,任何地方都可以访问,在构造函数的参数中使用public arg,则可以不用重新定义arg
存在于类本身上面而不是类的实例上,所以
static:静态属性,只能通过类名来调用,可以继承,通过子类的命名来调用,不可以使用this.来调用
举个栗子:
class Animal {
constructor(name:string){
this.name=name;
}
public skip(){}
private name:string; // 私有变量,不能被继承,也不能在外部被访问,只能在类“Animal”中访问
protected move() {
console.log(Animal.food); // 静态属性,只能这么调用
}
readonly amount:number = 4;
static food:string = 'rou';
}
// Cat继承Animal,并将构造函数设为私有
class Cat extends Animal{
private constructor(name:string){
super(name)
}
}
const cat = new Cat(); // 报错 类“Cat”的构造函数是私有的,仅可在类声明中访问
class Jiafei extends Cat{...} // 报错 无法扩展类“Cat”。类构造函数标记为私有
// Dog继承Animal
class Dog extends Animal {
constructor(name:string,public color:string){ // color变成实例属性,不需要再定义
super(name)
this.color = color;
}
private eat:string = '粑粑';
brek(){
this.amount = 2; // 报错 amount为只读,只能读取不可更改
this.name(); // 报错 属性“name”为私有属性,只能在类“Animal”中访问
this.skip(); // 正确 Animal中的public,可以访问
this.move(); // 正确 Animal中的protected,子类可以访问
this.eat = Animal.food; // 静态属性,只能这么调用
}
}
const dog = new Dog('狗狗','白色');
dog.move(); // 报错 属性“move”受保护,只能在类“Animal”及其子类中访问
dog.name; // 报错 属性“name”为私有属性,只能在类“Animal”中访问
dog.eat; // 报错 属性“color”为私有属性,只能在类“Dog”中访问
dog.skip(); // 正确 公用属性
dog.color; // 正确 公用属性
dog.brek();// 正确 公用属性
Dog.food; // 正确 可以通过子类的命名来调用
抽象类和多态
抽象类:只能被继承不能被实例化的类,abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法
好处:抽离出代码的公用性,有利于代码的复用性
// 创建一个抽象类Person;
abstract class Person {
eat(): void {
console.log('米饭');
}
abstract skin(): void; // skin为Person的抽象成员,必须在派生类中实现
}
// 派生类Person
class Chinese extends Person {
constructor(public name:string) {
super(); // 在派生类的构造函数中必须调用 super()
}
// Chinese不会自动继承Person的skin,所以要手动实现,否则报错
skin(): void{
console.log('黄皮肤')
}
}
const c = new Person(); // 报错 无法创建抽象类的实例
const chnese = new Chinese('中国人'); // 正确
多态:父类中定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现,也是继承的一种
上面的例子稍微变一变
// eat和skin方法在子类上有各自的实现逻辑,这就是多态
abstract class Person {
eat(): void{}
abstract skin(): void
}
class Chinese extends Person {
eat(): void{console.log('吃米饭')}
skin(): void{console.log('黄皮肤')}
}
class American extends Person {
eat(): void{console.log('吃面包')}
skin(): void{console.log('白皮肤')}
}
const chnese = new Chinese(); // 正确
const american = new American(); // 正确
const personArr:Person[] = [chnese, american];
personArr.forEach(item=>{
item.eat();
item.skin();
})
拓展
链式调用:类里面的方法返回this,子类可以继承,可以保持父类子类调用的连贯性
// 这就实现了一个简单的链式调用
class ParentChain{
ch1(){return this};
ch2(){return this};
}
const parentChain = new ParentChain();
parentChain.ch1().ch2()
// 子类可以继承。
class MyChain extends ParentChain{
next(){return this;}
}
const myChain = new MyChain();
myChain.next().ch2().next().ch1(); // 子类父类相互调用