TypeScript类的使用(六)

2022-09-21  本文已影响0人  未路过

1.类的定义

  1. 使用class关键字来定义一个类;
  2. 我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型
  1. 类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用;
  1. 类中可以有自己的函数,定义的函数称之为方法;
    js
      class Person {
        name = "why";
        age = 18;
        eating() {
          console.log("eating");
        }
      }

这里面的name和age都是在Person这个函数自身的,eating是在Person的prototype上的。
Class 的基本语法 - ECMAScript 6入门 (ruanyifeng.com)
ES2022 为类的实例属性,又规定了一种新写法。实例属性现在除了可以定义在constructor()方法里面的this上面,也可以定义在类内部的最顶层。

// 原来的写法
class IncreasingCounter {
  constructor() {
    this._count = 0;
  }
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}

上面示例中,实例属性_count定义在constructor()方法里面的this上面。

现在的新写法是,这个属性也可以定义在类的最顶层,其他都不变。

class IncreasingCounter {
  _count = 0;
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}

ts中类的写法

class Person {
//定义属性的时候必须初始化值
  name: string = ""
  age: number = 0

  eating() {
    console.log(this.name + " eating")
  }
}

const p = new Person("why", 18)
console.log(p.name)
console.log(p.age)
p.eating()

export {}

或者
在constructor里面做初始化

class Person {
  name: string
  age: number

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

  eating() {
    console.log(this.name + " eating")
  }
}

const p = new Person("why", 18)
console.log(p.name)
console.log(p.age)
p.eating()

export {}

2. 类的继承

  1. 面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。
  2. 我们使用extends关键字来实现继承,子类中使用super来访问父类。
  3. 我们来看一下Student类继承自Person:
class Person {
  name: string = ""
  age: number = 0

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

class Student extends Person {
  sno: number = 0

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

class Teacher extends Person {
  title: string = ""

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

const stu = new Student()
stu.name = "coderwhy"
stu.age = 10
console.log(stu.name)
console.log(stu.age)
stu.eating()

使用super的继承

class Person {
  name: string
  age: number

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

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

class Student extends Person {
  sno: number

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

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

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

const stu = new Student("why", 18, 111)
console.log(stu.name)
console.log(stu.age)
console.log(stu.sno)

stu.eating()

export {}


类的多态

class Animal {
  action() {
    console.log("animal action")
  }
}

class Dog extends Animal {
  action() {
    console.log("dog running!!!")
  }
}

class Fish extends Animal {
  action() {
    console.log("fish swimming")
  }
}

class Person extends Animal {

}

// animal: dog/fish
// 多态的目的是为了写出更加具备通用性的代码
function makeActions(animals: Animal[]) {
  animals.forEach(animal => {
    animal.action()//执行的是重写之后的方法
  })
}
//其实对于我们makeActions里面的参数中的每个元素来说,
//就是我们看起来是相同的类型,都是animal类型,
//但是在真正执行我们方法的时候,他们表现出来的形态是不一样的,就是我也是执行action的时候,执行的是各自的action

makeActions([new Dog(), new Fish(), new Person()])

3. 类的成员修饰符

  1. 在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected
    • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;其他地方都能访问。
    • private 修饰的是仅在同一类中可见、私有的属性或方法;实例不能访问privita属性。
    • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;
  2. public是默认的修饰符,也是可以直接访问的,我们这里来演示一下protected和private。
class Person {
  private name: string = ""

  // 封装了两个方法, 通过方法来访问name
  getName() {
    return this.name
  }

  setName(newName) {
    this.name = newName
  }
}

const p = new Person()
console.log(p.getName())
p.setName("why")

export {}

protected

// protected: 在类内部和子类中可以访问

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

class Student extends Person {
  getName() {
    return this.name
  }
}

const stu = new Student()
console.log(stu.getName())

export {}

4. 只读属性readonly

如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly:
只读属性在constructor中赋值的比较多。只读属性是可以在constructor中赋值的。

class Person {
  // 1.只读属性是可以在构造器中赋值, 赋值之后就不可以修改
  // 2.属性本身不能进行修改, 但是如果它是对象类型, 对象中的属性是可以修改
  readonly name: string
  age?: number
  readonly friend?: Person
  constructor(name: string, friend?: Person) {
    this.name = name
    this.friend = friend
  }
}

const p = new Person("why", new Person("kobe"))
console.log(p.name)
console.log(p.friend)

// 不可以直接修改friend
// p.friend = new Person("james")
if (p.friend) {
  p.friend.age = 30
} 

// p.name = "123"

5.getters/setters

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

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

  // 访问器setter/getter
  // setter
  set name(newName) {
    this._name = newName
  }
  // getter
  get name() {
    return this._name
  }
}

const p = new Person("why")
p.name = "coderwhy"
console.log(p.name)

6. 静态成员

  1. 前面我们在类中定义的成员和方法都属于对象级别的, 在开发中, 我们有时候也需要定义类级别的成员和方法。就是直接通过类来获取它的方法和属性。
  2. 在TypeScript中通过关键字static来定义:
// class Person {
//   name: string = ""
//   age: number = 12
// }

// const p = new Person()
// p.name = "123"

class Student {
  static time: string = "20:00"

  static attendClass() {
    console.log("去学习~")
  }
}

console.log(Student.time)
Student.attendClass()


7. 抽象类abstract

  1. 我们知道,继承是多态使用的前提。
  1. 什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。

抽象类有如下的特点:


function makeArea(shape: Shape) {
  return shape.getArea()
}


abstract class Shape {
  abstract getArea(): number
}


class Rectangle extends Shape {
  private width: number
  private height: number

  constructor(width: number, height: number) {
    super()
    this.width = width
    this.height = height
  }

  getArea() {
    return this.width * this.height
  }
}

class Circle extends Shape {
  private r: number

  constructor(r: number) {
    super()
    this.r = r
  }

  getArea() {
    return this.r * this.r * 3.14
  }
}

const rectangle = new Rectangle(20, 30)
const circle = new Circle(10)

console.log(makeArea(rectangle))
console.log(makeArea(circle))
// makeArea(new Shape())

// makeArea(123)
// makeArea("123")


6. 类的类型

类本身也是可以作为一种数据类型的:
把一个类作为类型,然后放到某一个位置,这个就叫做类的类型.

class Person {
  name: string = "123";
  eating() {}
}

const p = new Person();

const p1: Person = {
  name: "why",
  eating() {},
};
//p1的类型是Person的话,
//那必须要有name属性和eating方法,必须和Person里面的实例成员保持一致

function printPerson(p: Person) {
  console.log(p.name);
}

printPerson(new Person());
printPerson({ name: "kobe", eating: function () {} });
//这两个等价
export {};

上一篇下一篇

猜你喜欢

热点阅读