TypeScript 第三章:类 class


类的定义

下面是使用 TS 约束属性并实例化对象

class User {
    
    
    name: string
    age: number
    constructor(name: string, age: number) {
    
    
        this.name = name
        this.age = age
    }
    getInfo = (): string => {
    
    
        return `${
      
      this.name}的年龄是${
      
      this.age}`
    }
}

const hj = new User('hj', 19)
const hk = new User('hk', 20)
console.log(hj.getInfo()); // hj的年龄是19
console.log(hk.getInfo()); // hk的年龄是20

const users: User[] = [hj, hk]
console.log(users);
// [
//     User { getInfo: [Function (anonymous)], name: '张三', age: 19 },
//     User { getInfo: [Function (anonymous)], name: 'hk', age: 20 }
// ]

通过约束数组的类型为User,使其成员只能是 User 类型对象

...
const users: User[] = [hj, hk]
console.log(users);
...

修饰符

public

class User {
    
    
    public name: string
    public age: number
    constructor(name: string, age: number) {
    
    
        this.name = name
        this.age = age
    }
    public getInfo = (): string => {
    
    
        return `${
      
      this.name}的年龄是${
      
      this.age}`
    }
}

const hj = new User('hj', 19)
const hk = new User('hk', 20)
hj.name = '张三'

protected

protected 修饰符指受保护的,只允许在父类与子类使用,不允许在类的外部使用

class User {
    
    
    protected name: string
    public age: number
    constructor(name: string, age: number) {
    
    
        this.name = name
        this.age = age
    }
    public getInfo = (): string => {
    
    
        return `${
      
      this.name}的年龄是${
      
      this.age}` // 内部是可以访问 protected 的
    }
}

const hj = new User('hj', 19)
hj.name = '张三' // 属性“name”受保护,只能在类“User”及其子类中访问
console.log(hj.getInfo()); // 张三的年龄是19

private

private 修饰符指私有的,不允许在子类与类的外部使用

  • 子类不能访问父类的 private 属性或方法
class Person {
    
    
    protected name: string
    private age: number
    protected info = (): string => {
    
    
        return `${
      
      this.name}的年龄是${
      
      this.age}`
    }
}

class User extends Person {
    
    
    constructor(name: string, age: number) {
    
    
        super()
        this.name = name
        this.age = age // 子类不能访问父类的 private 属性或方法
    }
    public getInfo = (): string => {
    
    
        return this.info()
    }
}

const hj = new User('hj', 19)
console.log(hj.getInfo()); // hj的年龄是19

  • 父类声明 private 属性或方法子类不允许覆盖
class Person {
    
    
    protected name: string
    private age: number
    private getInfo = (): string => {
    
    
        return `${
      
      this.name}的年龄是${
      
      this.age}`
    }
}

// 类“User”错误扩展基类“Person”。
// 属性“getInfo”在类型“Person”中是私有属性,但在类型“User”中不是
class User extends Person {
    
    
    constructor(name: string, age: number) {
    
    
        super()
        this.name = name
    }
    public getInfo = (): string => {
    
    
        return `姓名:${
      
      this.name}`
    }
}

  • 修饰符 子类访问或更改父类属性或方法是有限制的
    • 父类的 private 不允许只类修改
    • 父类的 protected 子类可以修改为 protected 或 public
    • 父类的 public 子类只能设置为 public
class Person {
    
    
    protected name: string
    private age: number
}

// 类“User”错误扩展基类“Person”。
class User extends Person {
    
    
    private name: string // 属性“name”在类型“User”中是私有属性,但在类型“Person”中不是
    constructor(name: string, age: number) {
    
    
        super()
        this.name = name
    }
    public getInfo = (): string => {
    
    
        return `姓名:${
      
      this.name}`
    }
}

readonly

readonly 将属性定义为只读,不允许在类的内部与外部进行修改

类似于其他语言的 const 关键字

class User {
    
    
    protected name: string
    private age: number
    readonly sex: string
    constructor(name: string, age: number, sex: string) {
    
    
        this.name = name
        this.sex = sex
    }
    public getInfo = (): string => {
    
    
        return `姓名:${
      
      this.name},性别${
      
      this.sex}`
    }
}

const hj = new User('hj', 19, '男')
console.log(hj.sex); // 男
hj.sex = '保密' // 无法分配到 "sex" ,因为它是只读属性

constructor

构造函数是初始化实例参数使用的,在 TS 中有些细节与其他程序不同

我们可以在构造函数 constructor 中定义属性,这样就不用在类中声明属性了,可以简化代码量

必须要在属性前加上 public、private、readonly 等修饰符才有效

class User {
    
    
    constructor(public name: string) {
    
    }
    getInfo = () => {
    
    
        return this.name
    }
}
const hj = new User('hj')
console.log(hj.getInfo()); // hj

static

static 用于定义静态属性或方法,属性或方法是属于构造函数的

静态属性是属于构造函数的,不是对象独有的,所以是所有对象都可以共享的


语法介绍

下面是 static 使用的语法

class User {
    
    
    static sex: string = '保密'

    static getUserInfo() {
    
    
        return '性别是' + User.sex
    }
}
const hj = new User()
console.log(hj.getUserInfo()); // jsError 属性“getUserInfo”在类型“User”上不存在
console.log(User.getUserInfo()); // 性别是保密

单例模式

当把 construct 定义为非 public 修饰符后,就不能通过这个类实例化对象了。

class User {
    
    
    protected constructor() {
    
    

    }
}

const hj = new User(); // 类“User”的构造函数是受保护的,仅可在类声明中访问

我们可以利用这个特性再结合 static 即可实现单例模式,即只实例化一个对象

class User {
    
    
    static instance: User | null = null;
    protected constructor() {
    
     }

    public static make(): User {
    
    
        if (User.instance == null) User.instance = new User;

        return User.instance;
    }
}

const hj = User.make();
console.log(hj);

get/set

使用 get 与 set 访问器可以动态设置和获取属性,类似于 vue 或 laravel 中的计算属性

class User {
    
    
    constructor(public _name: string) {
    
    }
    
    public get name () {
    
    
        return this._name
    }

    public set name (value: string) {
    
    
        this._name = value
    }
}

const hj = new User('hj')

console.log(hj.name); // hj
hj.name = 'hk'
console.log(hj.name); // hk

abstract

抽象类定义使用 abstract 关键字,抽象类除了具有普通类的功能外,还可以定义抽象方法

  • 抽象类可以不包含抽象方法,但抽象方法必须存在于抽象类中
  • 抽象方法是对方法的定义,子类必须实现这个方法
  • 抽象类不可以直接使用,只能被继承
  • 抽象类类似于类的模板,实现规范的代码定义

下例中的子类都有 move 方法,我们可以在抽象方法中对其进行规范定义

class Animation {
    
    
    protected getPos() {
    
    
        return {
    
     x: 100, y: 300 }
    }
}

class Tank extends Animation {
    
    
    public move(): void {
    
    }
}

class Player extends Animation {
    
    
    public move(): void {
    
    }
}

  • 抽象方法只能定义,不能实现,即没有函数体
  • 子类必须实现抽象方法
abstract class Animation {
    
    
    abstract move(): void
    protected getPos() {
    
    
        return {
    
     x: 100, y: 300 }
    }
}

// 非抽象类“Tank”不会实现继承自“Animation”类的抽象成员“move”
class Tank extends Animation {
    
    
    // public move(): void {}
}

class Player extends Animation {
    
    
    public move(): void {
    
    }
}

const tank = new Tank()
const player = new Player()

  • 子类必须实现抽象类定义的抽象属性
abstract class Animation {
    
    
    abstract move(): void
    abstract name: string
    protected getPos() {
    
    
        return {
    
     x: 100, y: 300 }
    }
}

// 非抽象类“Tank”不会实现继承自“Animation”类的抽象成员“name”
class Tank extends Animation {
    
    
    // public name = '敌方'
    public move(): void {
    
    }
}

class Player extends Animation {
    
    
    public name = '玩家'
    public move(): void {
    
    }
}

const tank = new Tank()
const player = new Player()

抽象类不能被直接使用,只能被继承

abstract class Animation {
    
    
    abstract move(): void
    abstract name: string
    protected getPos() {
    
    
        return {
    
     x: 100, y: 300 }
    }
}

const animation = new Animation() // 无法创建抽象类的实例

猜你喜欢

转载自blog.csdn.net/qq_41887214/article/details/125534302