# 五.类

前言

# 1.ts 中定义类

class Pointer {
  x!: number; //实例上的属性必须先声明
  y!: number;
  constructor(x: number, y?: number, ...args: number[]) {
    this.x = x;
    this.y = y as number;
  }
}
let p = new Pointer(100, 200);
1
2
3
4
5
6
7
8
9

实例上的属性需要先声明再使用,构造函数中的参数可以使用可选参数和剩余参数

# 2.类中的修饰符

  • public修饰符(谁都可以访问到)
class Animal {
  public name!: string; //不写public默认也是公开的
  public age!: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class Cat extends Animal {
  constructor(name: string, age: number) {
    super(name, age);
    console.log(this.name, this.age); //子类访问
  }
}
let p = new Cat("Tom", 18);
console.log(p.name, p.age); //外层访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Animal {
  constructor(public name: string, public age: number) {
    this.name = name;
    this.age = age;
  }
}
1
2
3
4
5
6

我们可以通过参数属性来简化父类中的代码

  • protected修饰符(自己和子类可以访问到)
class Animal {
  constructor(protected name: string, protected age: number) {
    this.name = name;
    this.age = age;
  }
}
class Cat extends Animal {
  constructor(name: string, age: number) {
    super(name, age);
    console.log(this.name, this.age);
  }
}
let p = new Cat("Tom", 18);
console.log(p.name, p.age); //无法访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • private修饰符(除了自己都访问不到)
class Animal {
  constructor(private name: string, private age: number) {
    this.name = name;
    this.age = age;
  }
}
class Cat extends Animal {
  constructor(name: string, age: number) {
    super(name, age);
    console.log(this.name, this.age); //无法访问
  }
}
let p = new Cat("Tom", 18);
console.log(p.name, p.age); //无法访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • readonly修饰符(仅读修饰符)
class Animal{
  constructor(public readonly name:string,public age:number){
    this.name= name
    this.age = age
  }
  changeName(name:string){
    this.name = name://仅读属性只能在constructor中被赋值
  }
}
class Cat extends Animal{
  constructor(name:string,age:number){
    super(name,age)
  }
}
let p = new Cat('Tom',18)
p.changeName('Jerry')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

静态属性和静态方法是可以被子类所继承的

# 4.Super 属性

class Animal {
  say(message: string) {
    console.log(message);
  }
  static getType() {
    return "动物";
  }
}
class Cat extends Animal {
  say() {
    //原型方法中的super指代的是父类的原型
    super.say("喵喵叫");
  }
  static getType() {
    //静态方法中的super指代的是父类
    return super.getType();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 5.类的装饰器

# 5.1 装饰类

function addSay(target: any) {
  target.prototype.say = function () {
    console.log("say");
  };
}
@addSay
class Person {
  say!: Function;
}
let person = new Person();
person.say();
1
2
3
4
5
6
7
8
9
10
11

装饰类可以给类扩展功能,需要开启experimentalDecorators:true

# 5.2 装饰类中属性

function toUpperCase(target: any, key: string) {
  let value = target[key];
  Object.defineProperty(target.key, {
    get() {
      return value.toUpperCase();
    },
    set(newValue) {
      value = newValue;
    },
  });
}
function double(target: any, key: string) {
  let value = target[key];
  Object.defineProperty(target, key, {
    get() {
      return value * 2;
    },
    set(newValue) {
      value = newValue;
    },
  });
}
class Person {
  @toUpperCase
  name: string = "xiaomin";
  @double
  static age: number = 10;
  getName() {
    return this.name;
  }
}
let person = new Person();
console.log(person.getName(), Person.age);
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
31
32
33

装饰属性可以对属性的内容进行改写,装饰的是实例属性则 target 指向类的原型、装饰的是静态属性则 target 执行类本身

# 5.3 装饰类中方法

function noEnum(target: any, key: string, descriptor: PropertyDescriptor) {
  console.log(descriptor);
  descriptor.enumerable = false;
}
class Person {
  @toUpperCase
  name: string = "xiaomin";
  @double
  static age: number = 10;
  @noEnum
  getName() {
    return this.name;
  }
}
let person = new Person();
console.log(person); // getName 不可枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5.4 装饰参数

function addPrefix(target: any, key: string, paramIndex: number) {
  console.log(target, key, paramIndex);
}
class Person {
  @toUpperCase
  name: string = "JiangWen";
  @double
  static age: number = 10;
  prefix!: string;
  @noEnum
  getName(@addPrefix prefix: string) {
    return this.name;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6.抽象类

抽象类无法被实例化,只能被继承,抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现

abstract class Animal {
  name!: string;
  abstract speak(): void;
}
class Cat extends Animal {
  speak() {
    console.log("abc");
  }
}
class Dog extends Animal {
  speak(): string {
    console.log("3333");
    return "dsfasd";
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

定义类型时void表示函数的返回值为空(不关心返回值类型,所以在定义函数时也不关心函数返回值类型)