TypeScript中的类 Class

公共属性的修饰符:

  • public:公共,默认修饰符,外部和内部都能使用
  • private:私有的,只能内部类用,外部不能读写
  • protected:当前类和派生类(子类)可访问
  • readonly:外部只能读不能写
  • static:静态属性或静态方法

类的定义

class User {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

const u1 = new User("u1", 19);
const u2 = new User("u2", 20);
console.log(u1.getInfo()); // u1的年龄是19
console.log(u2.getInfo()); // u2的年龄是20

const users: User[] = [u1, u2];
console.log(users);

注意:

如果类中没有constructor ,则其中的属性需要初始化值,否则爆红

 如果类中有constructor ,但参数中没有给定义的属性赋值,也会爆红

class Person {
  name: string;
  age: number; //属性“age”没有初始化表达式,且未在构造函数中明确赋值

  constructor(name: string) {
    this.name = name;
  }
}

 public

  • 公共,默认修饰符,外部和内部都能使用

 

class User {
  public name: string;
  public age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  public getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

const u1 = new User("u1", 19);
console.log("u1:", u1);

u1.name = "张三";
console.log("u1_1:", u1);
  • 父类的 public, 子类只能设置为 public

class Person {
  public name: string = "";
  age: number = 0;
  public getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

// 类“User”错误扩展基类“Person”。
// 属性“getInfo”在类型“Person”中是私有属性,但在类型“User”中不是
class User extends Person {
  constructor(name: string) {
    super();
    this.name = name;
  }
  private getInfo = (): string => {
    return `姓名:${this.name}`;
  };
}

protected

protected 修饰符指受保护的,只允许在当前类与子类使用,不允许在类的外部使用

class User {
  protected name: string;
  public age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  public getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`; // 内部是可以访问 protected 的
  };
}

const u1 = new User("u1", 19);

u1.name = "张三"; // 属性“name”受保护,只能在类“User”及其子类中访问
console.log(u1.getInfo()); // 张三的年龄是19。虽然爆红,但依然能改
  • 父类的 protected ,子类可以修改为 protected 或 public,但不允许修改为private

class Person {
  name: string = "";
  age: number = 0;
  protected getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

// 类“User”错误扩展基类“Person”。
// 属性“getInfo”在类型“Person”中是私有属性,但在类型“User”中不是
class User extends Person {
  private getInfo = (): string => {
    return `姓名:${this.name}`;
  };
}

private

private 修饰符指私有的,不允许在子类与类的外部使用

  • 子类不能访问父类的 private 属性或方法

class Person {
  protected name: string = "";
  private age: number = 22;
  protected info = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

class User extends Person {
  constructor(name: string, age: number) {
    super();
    this.name = name;
    this.age = age; // 子类不能访问父类的 private 属性或方法
  }
  public getInfo = (): string => {
    return this.info();
  };
}

const u1 = new User("u1", 19);
console.log(u1.getInfo()); // u1的年龄是19
  • 父类声明的 private 属性或方法,子类不允许覆盖

class Person {
  protected name: string = "";
  private age: number = 0;
  private getInfo = (): string => {
    return `${this.name}的年龄是${this.age}`;
  };
}

// 类“User”错误扩展基类“Person”。
// 属性“getInfo”在类型“Person”中是私有属性,但在类型“User”中不是
class User extends Person {
  constructor(name: string, age: number) {
    super();
    this.name = name;
  }
  public getInfo = (): string => {
    return `姓名:${this.name}`;
  };
}

readonly

readonly 将属性定义为只读,不允许在类的内部与外部进行修改

class User {
  name: string;
  readonly sex: string;

  constructor(name: string, sex: string) {
    this.name = name;
    this.sex = sex;
  }
  test() {
    this.sex = "男"; //无法为“sex”赋值,因为它是只读属性
  }
}

const u1 = new User("u1", "男");
u1.sex = "保密"; // 无法为“sex”赋值,因为它是只读属性

constructor

构造函数是初始化实例参数使用的

我们可以在构造函数 constructor 中定义属性,这样就不用在类中声明属性了,可以简化代码量

必须要在属性前加上 public、private、readonly 等修饰符才有效

 

class User {
  constructor(public name: string) {}
  getInfo = () => {
    return this.name;
  };
}
const u1 = new User("u1");
console.log(u1.getInfo()); // u1

 派生类的构造函数必须包含 "super" 调用,如下:

 

class Person {
  name: string = "";
}
class User extends Person {
  constructor(name: string) {
    super();
    this.name = name;
  }
}

与普通函数相同,在构造函数中也可以定义可选参数、默认值参数和剩余参数。但是构造函数不允许定义返回值类型,因为构造函数的返回值类型永远为类的实例类型

 

class Person {
  public other: string[]
  constructor(public name: string, public age: number = 23, public isMan?: boolean, ...other: string[]) {
    this.name = name
    this.age = age;
    this.isMan = isMan;
    this.other = other
  }
}

let p = new Person("张三", 24, false, "hello", "123")
console.log("p:", p)

 static

static 用于定义静态属性或方法

 

class User {
  static sex: string = "保密";

  static getUserInfo() {
    return "性别是" + User.sex;
  }
}
console.log(User.sex); // 保密
console.log(User.getUserInfo()); // 性别是保密

 get/set

使用 get 与 set 访问器可以动态设置和获取属性

class User {
  constructor(public _name: string) {}

  public get name() {
    return this._name;
  }

  public set name(value: string) {
    this._name = value;
  }
}

const u1 = new User("u1");

console.log(u1.name); // u1
u1.name = "张三";
console.log(u1.name); // 张三

类实现接口  implements

类实现单个接口

interface IPerson {
  eat: () => void;
}

// 类实现接口
class p implements IPerson {
  eat() {
    console.log("吃饭");
  }
}

 类实现多个接口

interface IPerson {
  eat: () => void;
}

interface IPerson2 {
  run: () => void;
}

// 正常
class p implements IPerson, IPerson2 {
  eat() {
    console.log("吃饭");
  }
  run() {
    console.log("跑步");
  }
}

// 异常
class p2 implements IPerson, IPerson2 {
  eat() {
    console.log("吃饭");
  }
}

 类同时继承父类, 又实现单个或多个接口

interface IPerson {
  eat: () => void;
}

interface IPerson2 {
  run: () => void;
}

class User {}

// 正常
class p extends User implements IPerson, IPerson2 {
  eat() {
    console.log("吃饭");
  }
  run() {
    console.log("跑步");
  }
}

// 异常
class p2 extends User implements IPerson, IPerson2 {
  eat() {
    console.log("吃饭");
  }
}

类实现type

类既可以实现接口,也可以实现type

interface A {
  name: string;
  add: () => void
}
type B = {
  age: number,
  add: () => void
}

class C implements A {
  name = 'xx'
  add() {
    console.log('类实现接口')
  }
}

class D implements B {
  age = 20
  add() {
    console.log('类实现type')
  }
}

类继承 extends

 class B extends A {}

B称作派生类,或者子类。A称作基类,或者父类

 当派生类继承了基类后,就自动继承了基类的非私有成员

 

class Shape {
  color: string = 'black';

  switchColor() {
    this.color =
      this.color === 'black' ? 'white' : 'black';
  }
}

class Circle extends Shape { }

const circle = new Circle();

console.log(circle.color) // 'black'
circle.switchColor();
console.log(circle.color) // 'white'

 重写基类成员

在派生类中可以重写基类的成员变量和成员函数。

在重写成员变量和成员函数时,需要在派生类中定义与基类中同名的成员变量和成员函数 

class Shape {
  color: string = 'black';

  switchColor() {
    this.color =
      this.color === 'black' ? 'white' : 'black';
  }
}

class Circle extends Shape {
  color: string = 'red';

  switchColor() {
    this.color = this.color === 'red' ? 'green' : 'red';
  }
}

const circle = new Circle();

console.log(circle.color) // 'red'
circle.switchColor();
console.log(circle.color) // 'green'

 在派生类中,可以通过super关键字来访问基类中的非私有成员。当派生类和基类中存在同名的非私有成员时,在派生类中只能通过super关键字来访问基类中的非私有成员,无法使用this关键字来引用基类中的非私有成员。

class Shape {
  color: string = '黑色';

  switchColor() {
    this.color =
      this.color === '黑色' ? '白色' : '黑色';
  }
}

class Circle extends Shape {
  switchColor() {
    super.switchColor();
    console.log(`颜色是: ${this.color}`);
  }
}

const circle = new Circle();

circle.switchColor();  //颜色是: 白色
circle.switchColor();  //颜色是: 黑色

 若派生类重写了基类中的受保护成员,则可以将该成员的可访问性设置为受保护的或公有的。也就是说,在派生类中只允许放宽基类成员的可访问性

class Base {
  protected x: string = '';
  protected y: string = '';
  protected z: string = '';
}

class Derived extends Base {
  // 正确
  public x: string = '';

  // 正确
  protected y: string = '';

  // 错误!派生类不能够将基类的受保护成员重写为更严格的可访问性
  private z: string = '';
}

由于派生类是基类的子类型,因此在重写基类的成员时需要保证子类型兼容性,如下:

class Shape {
  color: string = 'black';

  switchColor() {
    this.color =
      this.color === 'black' ? 'white' : 'black';
  }
}

class Circle extends Shape {
  // 编译错误
  // 类型'(color: string) => void'不能赋值给类型'() => void'
  switchColor(color: string) { }
}

 派生类实例化

  •  在派生类的构造函数中必须调用基类的构造函数,否则将不能正确地实例化派生类。在派生类的构造函数中使用“super()”语句就能够调用基类的构造函数。

class Shape {
  color: string = 'black';

  constructor() {
    this.color = 'black';
  }

  switchColor() {
    this.color =
      this.color === 'black' ? 'white' : 'black';
  }
}

class Circle extends Shape {
  radius: number;

  constructor() {
    super();

    this.radius = 1;
  }
}

  在派生类的构造函数中,引用了this的语句必须放在“super()”调用的语句之后,否则将产生编译错误,因为在基类初始化之前访问类的成员可能会产生错误

class Shape {
  color: string = 'black';

  constructor() {
    this.color = 'black';
  }

  switchColor() {
    this.color =
      this.color === 'black' ? 'white' : 'black';
  }
}

class Circle extends Shape {
  radius: number;

  constructor() {
    this.radius = 1;
    //  ~~~~
    //  编译错误,必须先调用 'super' 再访问 'this'
    super();
    // 正确
    this.radius = 1;
  }
}

 在实例化派生类时的初始化顺序如下:

  1. 初始化基类的属性。
  2. 调用基类的构造函数。
  3. 初始化派生类的属性。
  4. 调用派生类的构造函数。

 

class Shape {
  color: string = 'black';   // 1

  constructor() {            // 2
    console.log(this.color);
    this.color = 'white';
    console.log(this.color);
  }
}

class Circle extends Shape {
  radius: number = 1;        // 3

  constructor() {            // 4
    super();

    console.log(this.radius);
    this.radius = 2;
    console.log(this.radius);
  }
}

const circle = new Circle();

 单继承

TypeScript中的类仅支持单继承,不支持多继承,但支持多重继承。也就是说,在extends语句中只能指定一个基类。

 

class A { }
class B { }

class C extends A, B { }

 支持多重继承,如下:

class A { }

class B extends A { }
class C extends B { }

类类型

类声明将会引入一个新的命名类型,即与类同名的类类型。类类型表示类的实例类型,它由类的实例成员类型构成。 

class Circle {
  radius: number = 0;
  area(): number {
    return Math.PI * this.radius * this.radius;
  }
}

interface CircleType {
  radius: number;
  area(): number;
}

// 正确
const a: Circle = new Circle();

// 正确
const b: CircleType = new Circle();

 在定义一个类时,实际上我们定义了一个构造函数。随后,我们可以使用new运算符和该构造函数来创建类的实例。我们可以将该类型称作类的构造函数类型,在该类型中也包含了类的静态成员类型。

class A {
  static x: number = 20;
  y: number = 100;
}

// 类类型,即实例类型
const a: A = new A();

interface AConstructor {
  new(): A;
  x: number;
}

// 类构造函数类型
const b: AConstructor = A;

console.log(a.y)  //100
console.log(b.x)  //20

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值