TypeScript类的使用(六)
2022-09-21 本文已影响0人
未路过
1.类的定义
- 使用class关键字来定义一个类;
- 我们可以声明一些类的属性:在类的内部声明类的属性以及对应的类型
- 如果类型没有声明,那么它们默认是any的;
- 我们也可以给属性设置初始化值;
- 在默认的strictPropertyInitialization模式下面我们的属性是必须初始
化的,如果没有初始化,那么编译时就会报错; - 如果我们在strictPropertyInitialization模式下确实不希望给属性初
始化,可以使用 name!: string语法;
- 类可以有自己的构造函数constructor,当我们通过new关键字创建一个实例时,构造函数会被调用;
- 构造函数不需要返回任何值,默认返回当前创建出来的实例;
- 类中可以有自己的函数,定义的函数称之为方法;
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. 类的继承
- 面向对象的其中一大特性就是继承,继承不仅仅可以减少我们的代码量,也是多态的使用前提。
- 我们使用extends关键字来实现继承,子类中使用super来访问父类。
- 我们来看一下Student类继承自Person:
- Student类可以有自己的属性和方法,并且会继承Person的属性和方法;
- 在构造函数中,我们可以通过super来调用父类的构造方法,对父类中的属性进行初始化;
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. 类的成员修饰符
- 在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected
- public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;其他地方都能访问。
- private 修饰的是仅在同一类中可见、私有的属性或方法;实例不能访问privita属性。
- protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法;
- 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. 静态成员
- 前面我们在类中定义的成员和方法都属于对象级别的, 在开发中, 我们有时候也需要定义类级别的成员和方法。就是直接通过类来获取它的方法和属性。
- 在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
- 我们知道,继承是多态使用的前提。
- 所以在定义很多通用的调用接口时, 我们通常会让调用者传入父类,通过多态来实现更加灵活的调用方式。
- 但是,父类本身可能并不需要对某些方法进行具体的实现,所以父类中定义的方法,,我们可以定义为抽象方法。
- 什么是 抽象方法? 在TypeScript中没有具体实现的方法(没有方法体),就是抽象方法。
- 抽象方法,必须存在于抽象类中;
- 抽象类是使用abstract声明的类;
抽象类有如下的特点:
- 抽象类是不能被实例的话(也就是不能通过new创建)
-
抽象方法必须被子类实现,否则该类必须是一个抽象类;
image.png
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 {};