公共属性修饰符

类的定义

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);

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。虽然爆红,但依然能改

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 修饰符私有的,不允许在子类与类的外部使用

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

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) { }
}

 派生类实例

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

 

原文地址:https://blog.csdn.net/qq_40323256/article/details/128482419

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_49767.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注