深入理解类

76 阅读4分钟

类的继承

继承的作用

  • 继承可以描述类与类之间的关系
  • 如果A和B都是类,并且可以描述为A是B,则A和B形成继承关系
    • B是父类,A是子类
    • B派生A, A继承自B
    • B是A的基类,A是B的派生类
  • 如果A继承自B,则A中自动拥有B中所有的成员

成员的重写

  • 重写(override):子类中覆盖父类的成员
  • 子类成员不能改变父类成员的类型
  • 无论是属性还是方法,子类都可以对父类的相对应成员进行重写,但重写时,需要保证类型的匹配
  • 需要注意this,在继承关系中,this的指向是动态的--调用方法时,根据具体的调用者确定this指向
  • super关键字:在子类的方法中,可以使用super关键字读取父类成员

类型匹配

鸭子辨型法:子类的对象,始终可以赋值给父类

如果需要判断一个数据的具体子类类型,可以使用instanceof

protected 修饰符

  • 受保护的成员,只能在自身和子类中访问

单根性和传递性

  • 单根性: 每个类最多只能拥有一个父类
  • 传递性:如果A是B的父类,并且B是C的父类,则可以认为A是C的父类
// 例子
class Tank{
    x: number = 0 
    y: number = 0
    name: string = '坦克'
    shoot(){
        console.log("发射子弹")
    }
    
    sayHello(){
        console.log(`我是一个${this.name}`)
    }
} 

class PlayerTank extends Tank{
    x: number = 20
    y: number = 20
    life: number = 5
    name: string = '玩家坦克'
    shoot() {
        console.log("玩家发射子弹")
    }
}

class EmemyTank extends Tank{
    name: string = '敌方坦克'
    shoot() {
        console.log("敌方发射子弹")
    }
    test() {
        super.sayHello()  // 我是一个玩家坦克
    }
}

const p = new PlayerTank()
p.sayHello() //我是一个玩家坦克
if(p instanceof PlayerTank){
    console.log(p.life)
}

抽象类

有时,某个类只表示一个抽象概念,主要用于提取子类共有的成员,而不能直接创建它的对象,该类可以作为抽象类

给类前面加上abstract,表示该类是一个抽象类,不可以创建一个抽象类的对象

抽象成员

父类中,有些成员是必须存在的,但是不知道该成员的值或实现是什么,因此,需要有一种强约束,让继承该类的子类,必须实现该成员

抽象类中,可以有抽象成员,这些抽象成员必须在子类中实现;三种实现方式

abstract class Chess{
    x: number = 0
    y: number = 0
    abstract readonly name: string;
    
    abstract move(targetX: number, tergetY: number): boolean;
}

class Horse extends Chess{
    readonly name: string  = '马 '
    move(targetX: number, tergetY: number): boolean{
        this.x = targetX
        this.y = targetY
        console.log("马移动成功")
        return true
    }
}

class Pao extends Chess{
    readonly name: string
    
    constructor(){
        super()
        this.name = "炮"
    }
    move(targetX: number, tergetY: number): boolean{
        this.x = targetX
        this.y = targetY
        console.log("炮移动成功")
        return true
    }
}

class Soldier extends Chess{
    get name() {
        return "兵"
    }
    move(targetX: number, tergetY: number): boolean{
        this.x = targetX
        this.y = targetY
        console.log("兵移动成功")
        return true
    }
}

const h = new Horse()
const p = new Pao()
const c = new Soldier()
h.move(1,2)
p.move(2,3)
c.move(3,4)

静态成员

静态成员是指:附着在类上的成员(属于某个构造函数的成员);使用static修饰的成员,是静态成员

实例成员: 对象成员,属于某个类的对象

静态成员:非实例成员,属于某个类

静态方法中的this

实例方法中的this指向的是当前对象

而静态方法中的this指向的是当前类

class User{
    constructor(  
        public loginId: string,
        public loginPwd: string,
        public name: string,
        public age: number
    ){}
    
    static login(loginId: string, loginPwd: string): User | undefined{
        return undefined
    }
}

const result = User.login("xxx", "123123 ")

索引器

对象[值],使用成员表达式

在TS中,默认情况下,不对索引器(成员表达式)做严格的类型检查

使用配置noImplicitAny: true 开启对隐式any的检查

隐式any: TS根据实际情况推导出的any类型

在索引器中,健的类型可以是字符串,也可以是数字

在类中,索引器书写的位置应该在所有成员之前

在JS中,所有的成员名本质上,都是字符串,如果使用数字作为成员名,会自动转换为字符串

作用

  • 在严格的检查下,可以实现为类动态增加成员
  • 可以实现动态操作类成员
const obj = {
    name: 'zero',
    age: 18
}

for(const key in obj) {
    console.log(key, obj[key])
}

// ts类的用法
const methodName = "sayHello"

class User{
    [prop: string]: any
    constructor(
        public name: string,
        public age: number
    ){}
    
    [methodName] (){}
}

const u = new User("zero", 18)
u[methodName]() 

// 不在构造函数的声明里
console.log(u["sex"])


class MyArray{
    [index: number]: string
    0: "1"
}

this指向约束

JS中this的几种情况

  • 如果直接调用函数(全局调用),this指向全局对象或undefined(启用严格模式)
  • 如果使用对象.方法调用,this指向对象本身
  • 如果是dom事件的处理函数,this指向事件处理对象

特殊情况

  • 箭头韩式,this在函数声明时确定指向,指向函数位置的this
  • 使用bind, apply, call手动绑定this对象

TS中的this

  • 配置noImplicitThis: true ,表示不允许this隐式的指向any
  • 允许在书写函数时,手动声明该函数中的this的指向,将this作为函数的第一个参数,该参数只用于约束this,并不是真正的参数,也不会出现在编译结果中
interface IUser{
    name: string
    age: number
    sayHello(this: IUser): void
}

const u: IUser = {
    name: 'zero',
    age: 18,
    sayHello() {
        console.log(this.name, this.age)
    }
}

const say = u.sayHello