【TypeScript】类的基本使用

文章目录

    • TypeScript类的基本使用
      • 类的介绍
      • 类的定义
      • 类的继承
      • 类成员的修饰符
      • 只读属性
      • getters/setters
      • 类的静态成员

TypeScript类的基本使用

类的介绍

在早期的JavaScript开发中( ES5)我们需要通过函数和原型链来实现类和继承,从ES6开始,引入了class关键字,可以更加方便的定义和使用类。

TypeScript作为JavaScript的超集,也是支持使用class关键字的,并且还可以对类的属性和方法等进行静态类型检测

实际上在JavaScript的开发过程中,我们更加习惯于函数式编程

比如React开发中,目前更多使用的函数组件以及结合Hook的开发模式;

比如在Vue3开发中,目前也更加推崇使用 Composition API;

但是在封装某些业务的时候,类具有更强大封装性,所以我们也需要掌握它们

类的定义我们通常会使用class关键字:

在面向对象的世界里,任何事物都可以使用类的结构来描述;

类中包含特有的属性和方法;


类的定义

例如我们使用class关键字来定义一个Person类 ;

  • 我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型

类中如果类型没有声明,那么它们默认是any的;

我们也可以给属性设置初始化值;

在默认的strictPropertyInitialization模式下面我们的属性是必须初始化的

class Person {
  name: string = ""
  age: number = 0
}

如果没有初始化,那么编译时就会报错;

【TypeScript】类的基本使用_第1张图片

如果我们在strictPropertyInitialization模式下确实不希望给属性初始化,可以使用 name!: string语法;

class Person {
  name!: string
  age!: number
}

类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用

构造函数不需要返回任何值,默认返回当前创建出来的实例;

我们也可以使用构造函数constructor对属性进行初始化

class Person {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

类中可以有自己的函数,定义的函数称之为方法

class Person {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  eating() {
    console.log("is eating")
  }
  running() {
    console.log("is running")
  }
}

// 测试
const p = new Person("chenyq", 18)
console.log(p.name)
console.log(p.age)
p.eating()
p.running()

类的继承

面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提

我们使用extends关键字来实现继承,子类中使用super来访问父类

我们来看一下Student类和Teacher类继承自Person类:

Student类和Teacher类可以有自己的属性和方法,并且会继承Person的属性和方法;

class Person {
  name: string = ""
  age: number = 0

  eating() {
    console.log("eating")
  }
}

class Student extends Person {
  score: number = 0
  
  studying() {
    console.log("studying")
  }
}

class Teacher extends Person {
  title: string = ""
  teaching() {
    console.log("teaching")
  }
}

// 测试
const stu = new Student()
stu.name = "chenyq"
stu.age = 18
console.log(stu.name)
console.log(stu.age)
stu.eating()
stu.studying()

const tea = new Teacher()
tea.name = "kaisa"
tea.age = 20
console.log(tea.name)
console.log(tea.age)
tea.eating()
tea.teaching()

但是目前这种做法我们还需要在实例中对name, age属性赋值, 这种方式会很麻烦, 我们希望创建对象实例的时候就可以进行初始化

在构造函数中,我们可以通过super()方法, 来调用父类的构造方法,对父类中的属性进行初始化;

class Person {
  name: string
  age: number

  // 父类构造器
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  eating() {
    console.log("eating")
  }
}

class Student extends Person {
  score: number = 0

  constructor(name: string, age: number, score: number) {
    // 调用父类构造器
    super(name, age)
    this.score = score
  }
  
  studying() {
    console.log("studying")
  }
}

// 测试
const stu = new Student("chenyq", 18, 110)
console.log(stu.name)
console.log(stu.age)
console.log(stu.score)
stu.eating()
stu.studying()

目前我们调用的eating方法, 是由父类Person继承的, 当我们Student子类对父类方法不满意时, 我们可以重写

class Student extends Person {
  score: number = 0

  constructor(name: string, age: number, score: number) {
    // 调用父类构造器
    super(name, age)
    this.score = score
  }

  // 重写父类方法
  eating() {
    console.log("student eating")
  }
  
  studying() {
    console.log("studying")
  }
}

如果我们重写子类eating方法时, 又想让父类的eating方法也执行一次, 可以通过super调用

class Student extends Person {
  score: number = 0

  constructor(name: string, age: number, score: number) {
    // 调用父类构造器
    super(name, age)
    this.score = score
  }

  // 重写父类方法
  eating() {
    // 子类中是由super, 再让父类的方法也执行一次
    super.eating()
    // 重写的部分
    console.log("student eating")
  }
  
  studying() {
    console.log("studying")
  }
}

类成员的修饰符

在TypeScript中,类的属性和方法支持三种修饰符:public、 private、 protected

  • public修饰符: 是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;

例如下面代码中, 属性默认的修饰符是public, 因此可在任何地方访问

class Person {
  name: string = ""
}

// 测试
const p = new Person()
// 可以在任何地方访问类中的额name属性
p.name = "aaa"
  • private修饰符: 是仅在同一类中可见、私有的属性或方法;

private修饰的属性或方法, 只能在同一类中访问, 外部访问就会报错

class Person {
  private name: string = "a"

  getName() {
    return this.name
  }
}

// 测试
const p = new Person()
// p.name // 外部无法访问
console.log(p.getName())
  • protected修饰符: 是仅在类自身及子类中可见、受保护的属性或方法;

protected修饰符除自身类中可以访问之外, 子类中也可以访问, 外部同样无法访问到

class Person {
  protected name: string = "a"
}

class Student extends Person {
  getName() {
    // 子类中也可以访问到protected
    return this.name
  }
}

// 测试
const stu = new Student()
console.log(stu.getName())

只读属性

readonly准确的说也是一个修饰符, 使用readonly修饰符修饰的属性是一个只读属性

如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly修饰符

class Person {
  readonly name: string = "aaa"
}

// 测试
const p = new Person()
console.log(p.name)
// p.name = "bbb" // 只能读, 不能修改

但是只读属性是可以在constructor构造器中赋值的, 赋值之后同样不可修改, 演示如下

class Person {
  readonly name: string
  
  constructor(name: string) {
    this.name = name
  }
}

// 测试
const p = new Person("abc")
console.log(p.name)

getters/setters

在前面一些私有属性我们是不能直接访问的,或者某些属性我们想要监听它的获取(getter)和设置(setter)的过程, 这个时候我们可以使用访问器

访问器的定义是类似一个函数的形式, 而调用又和一般函数不一样, 类似于属性的方式

class Person {
  private _name: string
  constructor(name: string) {
    this._name = name
  }

  // 访问器 setter/getter定义方式
  set name(newName) {
    this._name = newName
  }

  get name() {
    return this._name
  }
}

// 测试
const p = new Person("abc")
// 访问器的访问方式
p.name = "aaa"
console.log(p.name)

类的静态成员

面我们在类中定义成员的属性和方法都属于对象实例的, 但是在开发中, 我们有时候也需要定义类级别的成员和方法(也就是类属性、类方法)

在TypeScript中通过关键字static来定义

class Student {
  // 定义类的属性
  static time: string = "20:00"

  // 定义类方法
  static studying() {
    console.log("去上课学习")
  }
}

// 测试
console.log(Student.time)
Student.studying()

你可能感兴趣的:(TypeScript,typescript,javascript,前端)