Skip to content

类的声明 & 实现

TS为成员属性和构造函数的参数添加了类型注解 run方法默认返回值是void

typescript
class Dog {
  constructor(name: string) {
    this.name = name
  }
  name: string
  run() {}
}

image.png

image.png

注:

无论是在ES还是TS中,类的成员属性都是实例属性(而不是原型属性),类的成员方法都是原型方法

打印类的原型,查看是否包含内部属性

typescript
console.log(Dog.prototype)

image.png

类的原型不包含内部属性,原型上只有 run 方法和 constructor 构造方法

创建一个实例,并且输出

typescript
class Dog {
  constructor(name: string) {
    this.name = name
  }
  name: string
  run() {}
}

console.log(Dog.prototype)

let dog = new Dog('wangcai')
console.log(dog)

image.png

可以看到,内部属性 name 只在实例上,而不在原型上

异同点:

  • 在TS实例的属性必须有初始值,或在构造函数中被初始化
  • 如删掉构造函数中对name的初始化,将提示错误
  • 如下代码所示:
typescript
class Dog {
  constructor(name: string) {
    // this.name = name;
  }
  name: string
  run() {}
}

console.log(Dog.prototype)

let dog = new Dog('wangcai')
console.log(dog)

image.png

处理:

typescript
// 初始值
{
  class Dog {
    constructor(name: string) {
      // this.name = name;
    }
    name: string = 'Dog'
    run() {}
  }

  console.log(Dog.prototype)

  let dog = new Dog('wangcai')
  console.log(dog)
}

// 可选属性
{
  class Dog {
    constructor(name: string) {
      // this.name = name;
    }
    name?: string
    run() {}
  }

  console.log(Dog.prototype)

  let dog = new Dog('wangcai')
  console.log(dog)
}

总结:只要内部属性有初始值,就不会报错

继承

类的继承使用了extends关键字 类的构造函数constructor中调用了super,代表父类实例 父类Dog的构造函数中有一个参数name,所以子类也必须要有具有此参数

typescript
// 继承
class Husky extends Dog {
  constructor(name: string, color: string) {
    super(name)
    this.color = color
  }
  color: string
}

成员修饰符

类的成员修饰符部分是TS对ES所做的扩展

公有成员-public

类的所有属性默认均为public,表示对所有人可见

typescript
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
}

私有成员-private

私有成员,只能在类的本省调用,而不能被类的实例调用,也不能被子类调用

typescript
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  // name: string = 'dog'
  run() {}
  // 私有成员,只能在类的本省调用,而不能被类的实例调用,也不能被子类调用
  private pri() {}
}

let dog = new Dog('wangwang')
console.log(dog) // Dog {legs: 4, name: "wangwang"}
dog.pri()

image.png

私有成员也不能在子类中被调用

image.png

类的构造函数也可以被设置为私有成员,既不能被实例化也不能被继承了

typescript
// 类
class Dog {
  private constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
}

let dog = new Dog('wangwang')

class Husky extends Dog {
  constructor(
    name: string,
    public color: string
  ) {
    super(name)
    this.color = color
  }
}

image.png

受保护成员-protected

受保护成员,只能在类或者子类访问与调用,而不能在类的实例访问

typescript
// 类
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
  protected pro() {}
}

let dog = new Dog('wangwang')
dog.pro()

// 继承
class Husky extends Dog {
  constructor(
    name: string,
    public color: string
  ) {
    super(name)
    this.color = color
    this.pro()
  }
  // color: string;
}

image.png

构造函数也可以被声明为 protected,使这个类只能被继承,不能被实例化,相当于声明了一个基类

typescript
// 类
class Dog {
  protected constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
  protected pro() {}
}

let dog = new Dog('wangwang')

// 继承
class Husky extends Dog {
  constructor(
    name: string,
    public color: string
  ) {
    super(name)
    this.color = color
    this.pro()
  }
  // color: string;
}

image.png

只读属性-protected

只读属性,这个属性不能被更改,而且不能被更改 和实例属性一样,类的只读属性必须被初始化

typescript
// 类
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
  protected pro() {}
  readonly legs: number = 4
}

let dog = new Dog('wangwang')
console.log(dog) // Dog {legs: 4, name: "wangwang"}

静态成员-static

类的静态成员只能通过类名来调用,不能通过子类来调用 类的静态成员可以被继承

typescript
// 类
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
  protected pro() {}
  readonly legs: number = 4
  static food: string = 'bones'
}

let dog = new Dog('wangwang')
console.log(dog.food)
console.log(Dog.food) // bones

// 继承
class Husky extends Dog {
  constructor(
    name: string,
    public color: string
  ) {
    super(name)
    this.color = color
    this.pro()
  }
}
console.log(Husky.food) // bones

image.png

构造函数的参数添加修饰符

除了类的成员可以添加修饰符外,构造函数的参数也可以添加修饰符 作用:将参数自动变成实例的属性,这样就可以省略在类中的定义

typescript
// 类
class Dog {
  constructor(name: string) {
    this.name = name
  }
  public name: string
  run() {}
  private pri() {}
  protected pro() {}
  readonly legs: number = 4
  static food: string = 'bones'
}

// 继承
class Husky extends Dog {
  constructor(
    name: string,
    public color: string
  ) {
    super(name)
    this.color = color
    this.pro()
  }
  color: string
}

image.png

抽象类的定义

抽象类只能被继承,不能被实例化 定义抽象类使用abstract关键字

typescript
abstract class Animal {}

let animal = new Animal()

image.png

抽象类的继承

继承抽象类,需要在子类中调用super方法

typescript
abstract class Animal {
  eat() {
    console.log('eat')
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super()
    this.name = name
  }
  name: string
  run() {}
}
let dog = new Dog('wangwang')
console.log(dog.name)

抽象类实现方法复用

在抽象类中可以定义方法(可以有具体实现,也可以是抽象方法),从而实现复用 抽象类可以抽离事物的共性,有利于代码的复用和扩展

typescript
abstract class Animal {
  eat() {
    console.log('eat')
  }
  abstract sleep(): void
}

class Dog extends Animal {
  constructor(name: string) {
    super()
    this.name = name
  }
  name: string
  sleep() {
    console.log('Dog sleep')
  }
}
let dog = new Dog('wangwang')
dog.eat()
dog.sleep()

class Cat extends Animal {
  sleep() {
    console.log('Cat sleep')
  }
}
let cat = new Cat()
cat.eat()
cat.sleep()

抽象类实现多态

通过在父类中定义抽象方法,在不同子类中对该方法进行不同实现, 从而在运行时根据不同子类对象表现为不同状态

typescript
abstract class Animal {
  eat() {
    console.log('eat')
  }
  abstract sleep(): void
}

class Dog extends Animal {
  constructor(name: string) {
    super()
    this.name = name
  }
  name: string
  sleep() {
    console.log('Dog sleep')
  }
}
let dog = new Dog('wangwang')
dog.eat()
dog.sleep()

class Cat extends Animal {
  sleep() {
    console.log('Cat sleep')
  }
}
let cat = new Cat()
cat.eat()
cat.sleep()

let animal: Animal[] = [dog, cat]
animal.forEach((i) => {
  i.sleep()
})

this类型

类的成员方法可以直接返回一个this,方便实现链式调用,即Builder模式

typescript
class WorkFlow {
  step1() {
    return this
  }
  step2() {
    return this
  }
}
new WorkFlow().step1().step2()

使用this实现多态

this代表实例本身,继承时,子类实例即可表现多态(this既可以是父类,也可以是子类)

typescript
class WorkFlow {
  step1() {
    return this
  }
  step2() {
    return this
  }
}
new WorkFlow().step1().step2()

class Myflow extends WorkFlow {
  next() {
    return this
  }
}

new Myflow().next().step1().next().step2()

接口对类的约束作用

接口能够对类的成员属性和类型进行约束(且只能约束类的公有成员) 注意: 类必须实现接口中声明的全部属性和方法 类可以新增独有的属性和方法

typescript
interface Human {
  // new(name: string): void
  name: string
  eat(): void
}

// 类实现接口的时候,必须实现接口所有声明的属性
// 接口只能约束类的共有成员
// 接口不能约束构造函数
class Asion implements Human {
  constructor(name: string) {
    this.name = name
  }
  name: string
  eat() {}
  sleep() {}
}

image.png

接口继承

接口和类一样,可以相互继承,且一个接口可以继承多个接口 接口的继承特性可以将可重用部分进行抽离,也可以将多个接口合并成一个接口

typescript
interface Human {
  // new(name: string): void
  name: string
  eat(): void
}

// 类实现接口的时候,必须实现接口所有声明的属性
// 接口只能约束类的共有成员
// 接口不能约束构造函数
class Asion implements Human {
  constructor(name: string) {
    this.name = name
  }
  name: string
  eat() {}
  sleep() {}
}

// 接口继承
interface Man extends Human {
  run(): void
}

// 具有另外行为的接口
interface Child {
  cry(): void
}

// 多个接口组合使用
interface Boy extends Man, Child {}

// 属性与方法
let boy: Boy = {
  name: '',
  run() {},
  eat() {},
  cry() {},
}

接口继承类

接口除了可以继承接口外,还可以继承类,相当于将类成员全部抽象出来,仅有类的结构而没有具体实现 注意: 接口抽离类成员时,不仅抽离了公共成员,也抽离了私有成员和受保护成员

typescript
class Auto {
  state = 1
  // private state2 = 0;
}
interface AutoInterface extends Auto {}

class C implements AutoInterface {
  state = 1
}

image.png

image.png

image.png

typescript
class Auto {
  state = 1
  // private state2 = 0;
  protected state3 = 3
}
interface AutoInterface extends Auto {}

class C implements AutoInterface {
  state = 1
  // private state2 = 2;
  protected state3 = 3
}

class Bus extends Auto implements AutoInterface {}

学习笔记出自于梁宵老师课程