TypeScript 中的 class
本文最后更新于:2022年4月22日 上午
TypeScript 中的 class
class 的基本使用
class Person {
  name: string;
  age: number; // 需要初始化值,否则 ts 检查报错
  constructor(name: string, age: number) {
    this.name = name; // 对于这种情况 Dart 中可以简写
    this.age = age;
  }
  sayName() {
    console.log(this.name);
  }
}
const xiaomin = new Person('小明', 18);
xiaomin.name = '小东';
// xiaomin.age = 18;
xiaomin.sayName();类的继承
一个类可以继承另外一个类,继承的类叫做 子类/派生类,被继承的类叫做 父类/基类/超类
在 TypeScript 中 如果 子类 写了 构造函数,则需要手动调用 super
class Person {
  name: string;
  age: number; 
  constructor(name: string, age: number) {
    this.name = name; 
    this.age = age;
  }
  sayName() {
    console.log(this.name);
  }
}
class Man extends Person {
  // constructor(name: string, age: number){
  //   super(name, age)  // 如果写了构造函数,就需要手动调用 super();
  // }
  printSex() {
    console.log('男生');
  }
}
const man = new Man('小明', 18); //当子类没有构造函数的时,会自动调用父类的构造函数
man.printSex();
public、private、protected 可见性修饰符
public
public 对于类中的 成员/属性,如果没有手动添加过 可见性修饰符,默认就是 public
class Person {
  name: string;
  // public name: string; 上述语法等同于该写法
  constructor(name: string) {
    this.name = name;
  }
}
const person = new Person('小明');
console.log(person);private
private 修饰的成员属性只能在类内部访问,子类和类的示例无法直接访问使用 ** private 修饰的成员属性或方法** 
TypeScript 在类中声明的 private 只是编译阶段的 private,如果强制忽略 TypeScript 的语法检测,子类和类的示例依旧可以访问到
class Person {
  // 在 js 运行阶段时依旧可以获取到 prefix 属性,这是因为 JavaScript 并不支持真正意义的 private;
  public name: string;
  private nation = '中国';
  constructor(name: string) {
    this.name = name;
  }
}
const person = new Person('小明');
// person.nation = '英国';  // ts 语法报错,运行阶段实际上是可以获取的
console.log(person);protected
受保护的类型,使用protected 修饰的属性可以在子类中访问,但是实例上不可以访问
class Person {
  public name: string;
  protected sex: string = '男'; // protected 修饰的属性可以在子类中访问,但是实例上不可以访问
  constructor(name: string) {
    this.name = name;
  }
}
class Man extends Person {
  constructor(name: string) {
    super(name);
  }
  saySex() {
    console.log(this.sex);    // 子类可以访问父类中用 protected 修饰的成员
  }
}
const man = new Man('小明');
man.saySex(); // 男
// man.sex = 'woman'; // ts 语法报错,实例不能访问受保护的类型属性或方法子类中如何获取 父类中的 私有属性
class Person {
  public name: string;
  private nation = '中国';
  constructor(name: string) {
    this.name = name;
  }
  getNation() {
    return this.nation;
  }
  setNation(nation: string) {
    this.nation = nation;
  }
}
class Man extends Person {
  printNation() {
    console.log(this.getNation());
  }
}
const man = new Man('小明');
// person.nation = '英国';  // ts 语法报错,运行阶段实际上是可以获取的
// man.printNation();      // 中国
// 通过调用子类中的方法来获取,或者实例也可以直接调用 getNation() 因为 该函数的声明是缺省的,默认是 public,如果将它的修饰符改为 protected 则实例无法调用
console.log(man.getNation());readonly
类的成员属性可以加上 readonly,一旦赋值后则无法再次修改
class Student {
  name: string;
  readonly grade: string;
  // 如果 可见性修饰符 和 只读修饰符 同时出现,则 readonly 放在可见性修饰符后面
  constructor(name: string, grade: string) {
    this.name = name;
    this.grade = grade;
  }
}
const stu = new Student('小明', '1班');
console.log(`${stu.name}的班级为:${stu.grade}`);
// stu.grade = '2班';    // 无法分配到 "grade" ,因为它是只读属性static 静态属性/方法
静态属性 和 方法 只能通过类去访问,不能通过类的实例去访问
class Student {
  public static school = '希望小学';
}
// Student.school = '实验小学';
console.log(Student.school);  // 实验小学静态属性注意事项
因为覆盖 Function 上的属性和方法时不安全的,所以例如 name,length,call,bind等不能定位有静态属性
class Student {
  // static name = 'hello';  // 静态属性“name”与构造函数“Student”的内置属性函数“name”冲突。ts(2699)
  // static length = 10;
  // static call = 'call';
}class 中的 getter 和 getter
getter 和 setter 可以来截取我们队属性的获取和设置
需要注意以下几点
如果只写了
get,没有写set,则该属性为readonly如果
set的参数没有写类型注解,则会根据get的返回值推导set和get的可见性修饰符必须一致,例如:不允许get为public,而set为private
    
class Person {
  _home = '';
  
  public get home() {
    return this._home;
  }
  public set home(value) {
    this._home = value;
  }
}
const person = new Person();
person.home = '成都';
console.log(person.home); // 成都abstract 抽象类
抽象类中的 属性 或者 方法 可以 不包含具体的实现 ,交给子类来实现
抽象方法 或者 抽象属性 都是没有具体的实现,**且抽象类不能 ** new
由于抽象类不能 new,所有一般 抽象类 是用来做一些基础逻辑的封装 
abstract class Info {
  abstract name: string;    // 使用 abstract 修饰,子类必须实现
  abstract sayName(): void; // 抽象类声明 函数和普通函数声明不太一致
  sayHell() {
    console.log('hello');
  }
}
class Person extends Info {
  name;
  constructor(name: string) {
    super();
    this.name = name;
  }
  sayName() {
    console.log(this.name);
  }
}
// new Info();      // 语法报错,不允许 new 抽象类
const person = new Person('小明');
person.sayName();
person.sayHell();声明类
如果我们想要限制 类的构造函数和实例类型,只通过一个 interface 显然是不够的,所以我们需要通过两个 interface来声明类的类型
interface IPerson {
  name: string;
  age: number;
  sayHello: () => void;
}
// 定义类的构造函数及其静态属性
interface IPersonClass {
  new (name: string, age: number): IPerson;
  ClassName: string;
}
// 通过双重约束来限制类的静态类型和类的实例类型
const PersonClass: IPersonClass = class Person implements IPerson {
  name: string;
  age: number;
  static ClassName = 'person';
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  sayHello() {
    console.log("I' m " + this.name + ', hello');
  }
};
const p = new PersonClass('小明', 18);
p.sayHello();  // I' m 小明, hello
构造函数简写方式
以上代码也可以简写成以下方式
interface IPerson {
  name: string;
  age: number;
  sayHello: () => void;
}
// 定义类的构造函数及其静态属性
interface IPersonClass {
  new (name: string, age: number): IPerson;
  ClassName: string;
}
// 通过双重约束来限制类的静态类型和类的实例类型
const PersonClass: IPersonClass = class Person implements IPerson {
  static ClassName = 'person';
  
  // 会自动将传入的参数添加到 this
  constructor(public name: string, public age: number) {}
  sayHello() {
    console.log("I' m " + this.name + ', hello');
  }
};
const p = new PersonClass('小明', 18);
p.sayHello();
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处。