关键字 class

class Greeter {
  greetering: string;
  constructor(message: string){
    this.greetering = message;
  }
  // 在使用任何类成员是都使用this关键字
  greet() {
    return 'Hello, ' + this.greetering;
  }
}
let greeter = new Greeter('world');

继承

基于类的程序设计中,一种最基本的模式是允许使用继承来扩展现有的类

  • 类从基类中继承了属性和方法
  • 派生类手动包含构造函数时,必须调用super(),他会执行基类的构造函数,在构造函数里访问this的属性之前,必须要先调用super(),这是TS强制执行的重要规则
// 基类或者超类
class Animal {
  name: string;
  constructor(theName: string){
    this.name = theName;
  }
  move(distanceInMeters: number = 0){
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}
// 派生类或者子类
class Snake extends Animal {
  constructor(name: string){
    super(name);
  }
  // 重写父类方法
  move(distanceInMeters = 5){
    console.log('Slithering...');
    super.move(distanceInMeters);
  }
}
class Horse extends Animal {
  constructor(name: string){
    super(name);
  }
  move(distanceInMeters = 45){
    console.log('Galloping...');
    super.move(distanceInMeters);
  }
}

let sam = new Snake('Sammy the Python');
// 即使定义成Animal类型,但是他的值是House,所以调用move时,会调用Horse里重写的方法
let tom: Animal = new Horse('Tommy the Palomino');

sam.move();
tom.move(34);

成员修饰符

  • public:定义类成员时如果不加修饰符那么默认为public,可以随意访问类中定义的成员
  • private:不能在声明他的类的外部访问
  • protected:与private相似,但是protected成员在派生类(子类)中仍然可以访问
  • readonly:将属性设置为只读的,只读属性必须在声明时或构造函数里被初始化
// public 类型 
class Person2 {
  public name: string;
  public constructor(theName: string){
    this.name = theName;
  }
  public move(distanceInMeters: number){
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}
// private类型
class Person1 {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}
let person = new Person1("Book");
person.name; // error name是私有的访问不到
// protected类型
class Person {
  protected name: string;
  constructor(name: string){
    this.name = name;
  }
}
class Employ extends Person {
  private department: string;
  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }
  public getElevatorPitch() {
    return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}
let howard = new Employ('Howard', 'Sales');
console.log(howard.getElevatorPitch());
console.log(howard.name) // error protected 类型外部无法访问
// readonly类型
class Octopus {
  readonly name: string;
  readonly numberOfLegs: number = 8;
  constructor(theName: string){
    this.name = theName;
  }
}
let dad = new Octopus('Man with the 8 strong legs');
dad.name = 'Ald'; // error name属性是只读的
console.log(dad.name)

注:构造函数也可以被标记为protected,意味着这个类不能在包含他的类外被实例化,但能被继承

// 构造函数也可以被标记为protected,意味着这个类不能在包含他的类外被实例化,但能被继承
class Person3 {
  protected name: string;
  protected constructor(theName: string){
    this.name = theName;
  }
}
class Employee3 extends Person3{
  private department: string;
  constructor(name: string, department: string){
    super(name);
    this.department = department;
  }
  public getElement(){
    return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}
let hward = new Employee3('Howrl',"Sales");
let john = new Person3('John'); // error Person3的构造函数是被保护的

描述:TS使用的是结构性类型系统,当比较两种不同类型时,并不在乎他们从何处而来,如果所有成员类型都是兼容的,就认为他们的类型是兼容的

class Animal1 {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}
class Rhino extends Animal1 {
  constructor(){
    super('Rhino');
  }
}
class Employee {
  private name: string;
  constructor(theName: string) {
    this.name = theName;
  }
}
let animal = new Animal1('Goat');
let rhino = new Rhino();
let employee = new Employee('Bob');
// animal跟rhino共同继承自基类Animal1 所以出处是一样的,所以类型是兼容的
animal = rhino;
// employee是独立的虽然字段一样,但是出处不同,所以TS会认为类型不兼容
animal = employee; // error animal 与 employee不兼容

特殊:当比较带有private或protected成员的类型的时候,如果其中一个类型里包含一个private成员,那么只有当另外一个类型中也存在这样一个private成员,并且他们都来自同一处声明时,才认为这两个类是兼容的,protected同样适用

参数属性

可以方便的在一个地方定义并初始化一个成员
定义:参数属性通过给构造函数参数前面添加一个访问限定符来声明,使用private限定一个参数属性会声明并初始化成一个私有成员,public,protected类似

class Octopus1 {
  readonly numberOfLegs: number = 8;
  // 直接在构造函数中创建跟初始化name成员,把声明跟赋值合并
  constructor(readonly name: string){}
}

存取器

TS通过getters/setters来截取对对象成员的访问,可以有效控制对象成员访问
注意:

  • 存取器支持ES5或者更高版本
  • 只有带get不带set的存取器自动被推断为readonly
let passcode = 'secret passcode';
class Employee4{
  private _fullName: string;
  get fullName(): string {
    return this._fullName;
  }
  set fullName(newName: string){
    if(passcode && passcode == 'secret passcode'){
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}
let employee4 = new Employee4();
employee4.fullName = 'Bob Smith';
if(employee4.fullName){
  console.log(employee4.fullName);
}

静态属性

类实例成员:只有在类被实例化的时候才会被初始化,并且通过this.访问实例成员

静态属性:属性存在于类本身上而不是实例上,使用static关键字定义,通过构造函数名.来访问静态成员

class Grid {
  static origin = { x: 0, y: 0 };
  calculateDistanceFromOrigin(point: { x: number; y: number; }){
    let xDist = (point.x - Grid.origin.x);
    let yDist = (point.y - Grid.origin.y);
    return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  }
  constructor(public scale: number){}
}
let grid1 = new Grid(1.0);
let grid2 = new Grid(5.0);
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

抽象类

作为其他派生类的基类使用,一般不会被实例化
注:不同于接口,抽象类可以包含成员的实现细节
关键字:abstract关键字用来定义抽象类或者抽象类内部的抽象方法

抽象类特征:

  • 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
  • 抽象方法的语法与接口方法相似,两者都是定义方法签名但不包含方法体
  • 抽象方法必须包含abstract关键字并且可以包含访问修饰符
// 定义
abstract class Animal4{
  abstract makeSound(): void;
  move(): void {
    console.log('roaming the earch...');
  }
}

abstract class Department {
  constructor(public name: string){}
  printName(): void {
    console.log('Department name: ' + this.name);
  }
  abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
  constructor(){
    super('Accounting and Auditiing'); // 派生类构造函数必须调用super()
  }
  printMeeting(): void {
    console.log('The Accounting Department meets each Monday at 10am.');
  }
  generateReports(): void {
    console.log('Generating accounting reports...');
  }
}
let departMent: Department; // 允许创建一个对抽象类型的引用
// departMent = new Department(); // error 不能创建一个抽象类型的实例
departMent = new AccountingDepartment(); // 允许对一个抽象类子类进行实例化跟赋值
departMent.printName();
departMent.printMeeting();
// departMent.generateReports(); // error 方法在声明的抽象类中不存在

构造函数

当在TS中声明了一个类时,实际上同时声明了很多东西:

  • 实例的类型
  • 创建了一个构造函数,构造函数会在使用new创建类实例的时候被调用,这个构造函数也包含了类的所有静态属性
class Greeter1 {
  greeting: string;
  constructor(message: string){
    this.greeting = message;
  }
  greet() {
    return 'Hello, ' + this.greeting;
  }
}
// Greeter1类的实例的类型是Greeter1
let greete: Greeter1;
greete = new Greeter1('world');
console.log(greete.greet());

把类当做接口使用:
因为类定义会创建两个东西:类的实例类型、一个构造函数
因为类可以创建类型,所以能够在允许使用接口的地方使用类

class Point {
  x: number;
  y: number;
}
interface Point3d extends Point{
  z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
console.log(point3d);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容