0%

【051】typescript:类(class)

类描述了所创建的对象共同的属性和方法。

最基本的类

1
2
3
4
5
6
7
8
9
// ts
class Person<T> {}

// 编译成js后
var Person = /** @class */ (function () {
function Person() {
}
return Person;
}());

简单使用

定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):

  1. 字段:字段是类里面声明的变量。字段表示对象的有关数据。
  2. 构造函数:类实例化时调用,可以为类的对象分配内存。
  3. 方法:方法为对象要执行的操作。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // ts
    class Person<T> {
    // 字段
    name: string
    // 构造函数
    constructor(name: string) {
    this.name = name
    }
    // 方法
    getName() {
    return this.name
    }
    }
    const person = new Person('老王')
    console.log(person.getName()) // 老王

    // 编译成js后
    var Person = /** @class */ (function () {
    // 构造函数
    function Person(name) {
    this.name = name;
    }
    // 方法
    Person.prototype.getName = function () {
    return this.name;
    };
    return Person;
    }());
    var person = new Person('老王');
    console.log(person.getName());

new 关键字

我们使用 new 关键字来实例化类的对象,类实例化时会调用构造函数,类中的字段属性和方法可以使用 . 号来访问。完整实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person<T> {
// 字段
name: string
// 构造函数
constructor(name: string) {
this.name = name
}
// 方法
getName() {
return 'getName: ' + this.name
}
}
// 创建一个对象
const person = new Person('老王')
// 访问字段
console.log(person.name) // 老王
// 访问方法
console.log(person.getName()) // getName: 老王

类的继承

顾名思义,子类继承父类后,可以使用父类的属性和方法。但是要注意的是,子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person<T> {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
class Info extends Person<unknown> {
sex: string
constructor(name: string, age: number, sex: string) {
super(name, age)
this.sex = sex
}
getInfo() {
return `姓名:${this.name},年龄:${this.age},性别:${this.sex}`
}
}
const info = new Info('翠花', 18, '女')
console.log(info.getInfo()) // 姓名:翠花,年龄:18,性别:女

多重继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Person<T> {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
class Like extends Person<unknown> {
mylike: string
constructor(name: string, age: number, mylike: string) {
super(name, age)
this.mylike = mylike
}
}
class Info extends Like {
sex: string
constructor(name: string, age: number, mylike: string, sex: string) {
super(name, age, mylike)
this.sex = sex
}
getInfo() {
return `姓名:${this.name},年龄:${this.age},性别:${this.sex},爱好:${this.mylike}`
}
}
const info = new Info('翠花', 18, '游泳', '女')
console.log(info.getInfo()) // 姓名:翠花,年龄:18,性别:女,爱好:游泳

继承类的方法重写

子类得到父类的属性和方法后,我们相当于继承了父类的财产,那么在没有任何约束的情况下,我们就可以按照自己的意愿来使用这笔财产,在遇到父类和我们在使用这笔财产做法有出入时,我们便可以按照自己的方法来操作。这个过程称之为方法的重写。

1
2
3
4
5
6
7
8
9
10
11
12
class Father<T> {
loveFn() {
console.log('我是父类,我爱喝红牛')
}
}
class Son extends Father<unknown> {
loveFn() {
console.log('我是子类,我爱喝饮料')
}
}
const son = new Son()
son.loveFn() // 我是子类,我爱喝饮料

如果我们想要引用父类的属性和方法,可以使用 super 关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Father<T> {
loveFn() {
console.log('我是父类,我爱喝红牛')
}
}
class Son extends Father<unknown> {
loveFn() {
super.loveFn()
console.log('我是子类,我爱喝饮料')
}
}
const son = new Son()
son.loveFn() // 我是父类,我爱喝红牛 我是子类,我爱喝饮料

static 关键字

static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。

1
2
3
4
5
6
7
8
class Person<T> {
static person_name: string
static getName() {
return Person.person_name
}
}
Person.person_name = '翠花'
console.log(Person.getName()) // 翠花

instanceof 运算符

instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。

1
2
3
class Person<T> {}
const person = new Person()
console.log(person instanceof Person) // true

访问控制修饰符

TypeScript 支持 3 种不同的访问权限:

  1. public(默认):公有,可以在任何地方被访问。
  2. protected:受保护,可以被其自身以及其子类访问。
  3. private:私有,只能被其定义所在的类访问。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Person<T> {
    public name: string = '老王'
    private age: number = 30
    protected sex: string = '男'
    getAge() {
    return this.age
    }
    }
    class Sex extends Person<unknown> {
    getSex() {
    return this.sex
    }
    }
    const person = new Person()
    console.log(person.name) // 老王
    // console.log(person.age) // 报错,私有属性,只能在Person类中访问
    console.log(person.getAge()) // 30
    // console.log(person.sex) // 报错,保护属性,只能在Person类或Sex中访问
    const sex = new Sex()
    console.log(sex.getSex()) //男

类和接口

类使用关键字 implements 实现接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface Info {
name: string,
age: number
}
class Person implements Info {
name: string
age: number
sex: string
constructor(name: string, age: number, sex: string) {
this.name = name
this.age = age
this.sex = sex
}
getInfo() {
return `姓名:${this.name},年龄:${this.age},性别:${this.sex}`
}
}
const person = new Person('翠花', 18, '女')
console.log(person.getInfo()) // 姓名:翠花,年龄:18,性别:女

获取器/设置器

如果 get 存在但没有 set,则属性自动为 readonly
如果不指定 setter 参数的类型,则从 getter 的返回类型推断
getter 和 setter 必须有相同的 成员可见性

1
2
3
4
5
6
7
8
9
10
11
12
class Person {
_name: string
get name() {
return this._name
}
set name(n:string) {
this._name = n
}
}
const person = new Person()
person.name = '老王'
console.log(person._name) // 老王

static类中的块

静态块允许你编写具有自己作用域的语句序列,这些语句可以访问包含类中的私有字段。这意味着我们可以编写具有编写语句的所有功能的初始化代码,不会泄漏变量,并且可以完全访问我们类的内部结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
static _name: string
get name() {
return Person._name
}
set name(n: string) {
Person._name = n
}
static {
console.log('static类中的块')
Person._name = '老王'
}
}
const person = new Person()
console.log(person.name) // 老王
person.name = '翠花'
console.log(person.name) // 翠花

抽象类

在TypeScript中,可以使用 abstract 关键字来定义抽象类和抽象方法。抽象类不能被直接实例化,它只能被用作其他类的基类。抽象方法是没有实现的方法,必须在子类中被重写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 抽象类
abstract class A {
// 抽象属性
abstract name: string
// 抽象方法
abstract getName(): void
// 具体方法
setName(name: string) {
this.name = name
}
}
class B extends A {
name: string
constructor(name: string) {
super()
this.name = name
}
getName(): string {
return this.name
}
}
const b = new B('老王')
console.log(b.getName()) // 老王
b.setName('翠花')
console.log(b.getName()) // 翠花

小技巧

在以上方法中我们一直都使用构造函数初始化,如果我们不想在构造函数中初始化,可以找到 typescript 的配置文件 tsconfig.json 中的 strictPropertyInitialization,将其改为 false 即可。

1
2
3
4
class Person {
name: string
age: number
}