TS的进阶|抽象类、构造函数、继承、接口

465 阅读4分钟

u=1345530407,1122273143&fm=253&fmt=auto&app=120&f=JPEG.webp

TS给js扩展了一些概念抽象类、构造函数、继承、接口,让我们一起来了解一下ba~

抽象类

抽象类的特点

  1. 以abstract开头的类是抽象类和其它类区别不大,只是不能创建对象
  2. 抽象类是只能用来继承的类,没有办法实例对象
  3. 抽象类当中可以添加抽象方法
abstract class Animal {
  name: string
  constructor(name: string) {
    this.name = name
  }
  say() {
    console.log('你还好吗')
  }
  // 定义抽象方法没有方法体,只能定义到抽象类中,子类必须对抽象方法进行重写
  abstract listen(): void
}
class Dogs extends Animal {
  listen(): void {}
  say(): void {
    // 在类的方法中super表示当前类的父类
    // 在子类方法中引用父类或者父类的实例
    super.say()
  }
}
const cat = new Dogs('来福')

构造函数

class Person {
  name: string
  age: number
  //构造函数会在对象创建时调用
  constructor(name: string, age: number) {
    //在实例方法中this表示当前对象的实例
    // 在构造函数中当前对象就是当前新建的对象
    // 可以通过this向新建的对象中添加属性
    this.name = name
    this.age = age
  }
  say() {
    console.log('别和我讲法律')
  }
}
const dog = new Person('孙悟空', 18)
console.log(dog)

继承

使用extends实现类的继承

class Persons {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  say() {
    console.log('我想上天')
  }
}
class Dog extends Persons {
  run() {
    console.log(`我跑的贼快${this.name}`)
  }
}

const dogs = new Dog('旺财', 5)
dogs.run()

接口

  1. 用接口来定义一个类结构
  2. 接口用来定义一个类型结构,用来定义一个类型应该包含属性和方法
  3. 同时接口也可以当成类型声明去使用
  4. 接口可以在定义类的时候限制类的结构
  5. 接口中的所有属性都不能有实际的值
  6. 接口 只定义对象的结构,不考虑实际值,在接口中所有的方法都是抽象方法
interface myInter {
  name: string
  say(): void
}
// 定义类时,可以使类去实现一个接口,实现接口使类 满足接口的要求
class MyClass implements myInter {
  name: string
  constructor(name: string) {
    this.name = name
  }
  say(): void {
    throw new Error('Method not implemented.')
  }
}

属性的封装

  1. TS可以在属性前添加属性的修饰符(在ts中独有)
  2. public 修饰的属性可以在任意位置修改(默认值)
  3. privat 私有属性只能在类内部修改
  4. protected 受保护的属性,只能在当前类和当前类的子类中使用
  5. 通过在类中添加方法使私有属性可以被外部访问
class Person {
  public _name: string
  private _age: number
  constructor(name: string, age: number) {
    this._name = name
    this._age = age
  }
  // getter用来读取setter用来设置被称为属性读取器
  // 定义方法,用来获取age属性
  getAge() {
    return this._age
  }
  // 定义方法用来设置age属性
  setAge(value: number) {
    if (value >= 1) {
      this._age = value
    }
  }
}
const per = new Person('张三', 18)
console.log(per)

/**
 * 属性是在对象中设置的,属性可以任意修改
 * 属性可以任意修改就会导致对象中的数据变得非常不安全
 */
per._name = '李四'
// 属性“_age”为私有属性,只能在类“Person”中访问(报错)
per._age = 24
console.log(per)
// 私有化后设置和获取属性,如果不想修改就去掉get和set方法使属性为只读状态
console.log(per.getAge())
per.setAge(20)

TS中设置getter和setter的方法

get age() {
    return this._age
  }
  
set age(value: number) {
    if (value >= 1) {
      this._age=value
    }
}
per.age=33

protected 受保护的属性的使用方法

class Parent {
  protected num: number
  constructor(num: number) {
    this.num = num
  }
}
class Child extends Parent {
  test() {
    //如果设置私有属性private则访问不到
    console.log(this.num)
  }
}
const child = new Child(123)
// 属性“num”受保护,只能在类“Parent”及其子类中访问。(报错)
child.num=33

简写方式

可以将属性直接写在构造函数中

class Parent{
    constructor(public name:string,public age:number){
    }    
}
const p = new Parent('张三',18)

泛型

在类型不明确的时候整一个变量,

function fns<K>(a: K): K {
  return a
}
// 1.直接调用具有泛型的函数,泛型的值为number(ts的类型推断)
let result = fns(10)
// 手动指定ts泛型
let res = fns<string>('hello')

//2. 泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
  console.log(b)
  return a
}
fn2<number, string>(123, '456')

// 3.限制泛型范围
interface Inter {
  length: number
}
function fn3<T extends Inter>(a: T): number {
  // T extends Inter表示泛型T必须时Inter的实现类(子类)不一定传接口
  return a.length
}
fn3('123')

//不一定非要用接口
class My<T> {
  name: T
  constructor(name: T) {
    this.name = name
  }
}
const people = new My<string>('张三')