TypeScript的類

1. 類的定義

TypeScript中的類和ES6中類的定義類似,但是也有區(qū)別

class Person {
  name: string; // 和JAVA類似,要先在這聲明對象中擁有的屬性和類型,這里的分號很重要
  /*
    該屬性定義相當(dāng)于public name:string;
    只不過省略了public,下面再做解釋
  */
  constructor(n: string) {
    this.name = n; // 和ES6一樣,傳入構(gòu)造函數(shù),只不過需要在前面先定義this的屬性
  }

  run(): void {
    console.log(this.name);
  }
}

let p: Person = new Person("張三"); // 可以對實(shí)例類型變量進(jìn)行類型的定義,也可以默認(rèn)不寫為any
let Person2: typeof Person = Person; // 把Person類賦值Person2
// typeof Person是表明該對象是一個(gè)Person類的類型,而不是Person的實(shí)例類型
let p2: Person = new Person2('tt'); // 因?yàn)镻erson2也是Person類型的類,所以可以這樣實(shí)例對象
p.age = 18; // 報(bào)錯(cuò),類只允許有name屬性
p.run(); // 張三

對象屬性設(shè)置的時(shí)候需要在后面打上分號表示結(jié)尾,不像JS中對象寫法

constructor函數(shù)后面不能加上返回值的修辭符,否則會(huì)報(bào)錯(cuò),可以看作是固定寫法

函數(shù)定義完成后不需要加上符號分割


2. 類的繼承

類的繼承和接口不同,一個(gè)類只能繼承一個(gè)父類

class Person {
  name: string;
  constructor(n: string) {
    this.name = n;
  }
  run(): void {
    console.log(this.name);
  }
}

class Student extends Person { // 類的繼承可以說和ES6完全一樣,只是constructor需要指定類型
  age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }
  work() {
    console.log(this.age);
  }
}
let s = new Student("李四", 18);
s.run();
s.work(); // 18

如果子類里的方法和父類方法名一致,那么在使用的時(shí)候會(huì)使用子類的方法,不會(huì)使用父類的方法了


3. 類的修辭符

TypeScript中定義屬性或方法的時(shí)候?yàn)槲覀兲峁┝怂姆N修辭符

  • public:公有類型,在類、子類、類外部都可以對其訪問

    這里的在類外部訪問就是在實(shí)例化過后能在類的外界單獨(dú)打印該屬性,而不是只在內(nèi)部的方法中使用該屬性

  • protected: 保護(hù)類型,在類、子類里可以對其進(jìn)行訪問,但是在類的外部無法進(jìn)行訪問

  • private:私有類型,在類里面可以訪問,在子類和類的外部都無法訪問

    • TypeScript使用的是結(jié)構(gòu)性類型系統(tǒng),當(dāng)我們比較兩種不同的類型時(shí),并不在乎它們從何處而來,如果所有成員的類型都是兼容的,我們就認(rèn)為它們的類型是兼容的
    • 當(dāng)我們比較帶有 privateprotected成員的類型的時(shí)候,如果其中一個(gè)類型里包含一個(gè)private成員,那么只有當(dāng)另外一個(gè)類型中也存在這樣一個(gè) private成員,并且它們都是來自同一處聲明時(shí),我們才認(rèn)為這兩個(gè)類型是兼容的。對于 protected成員也使用這個(gè)規(guī)則
    class Animal {
      private name: string;
      constructor(theName: string) { this.name = theName; }
    }
    
    class Rhino extends Animal {
      constructor() { 
        super("Rhino"); 
      }
    }
    
    class Employee {
      private name: string;
      constructor(theName: string) { this.name = theName; }
    }
    
    let animal = new Animal("Goat");
    let rhino = new Rhino();
    let employee = new Employee("Bob");
    
    animal = rhino; // 能夠賦值,因?yàn)閮烧呒嫒?都是同一個(gè)私有屬性name
    

animal = employee; // 錯(cuò)誤: Animal 與 Employee 不兼容,name的私有屬性不兼容


`readonly`:只讀類型,可以使用 `readonly`關(guān)鍵字將屬性設(shè)置為只讀的,。只讀屬性必須在聲明時(shí)或構(gòu)造函數(shù)里被初始化

```typescript
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 = "Man with the 3-piece suit"; // 錯(cuò)誤! name 是只讀的.

如果屬性不添加修飾符,默認(rèn)為公有屬性(public)

// public
class Person {
  public name: string;
  constructor(n: string) {
    this.name = n;
  }
  public run(): void {
    console.log(this.name);
  }
}

class Student extends Person {
  constructor(name: string) {
    super(name);
  }
}
let s = new Student("李四");
console.log(s.name); // 李四
s.run(); // 李四
// protected
class Person {
  protected name: string;
  constructor(n: string) {
    this.name = n;
  }
  public run(): void { // 如果這個(gè)方法是protected,下面的s.run()也會(huì)報(bào)錯(cuò)
    console.log(this.name);
  }
}

class Student extends Person {
  constructor(name: string) {
    super(name);
  }
}
let s = new Student("李四");
console.log(s.name); // 報(bào)錯(cuò)
s.run(); // 李四

如果構(gòu)造函數(shù)也可以被標(biāo)記成 protected,意味著這個(gè)類不能在包含它的類外被實(shí)例化,但是能被繼承

class Person {
  protected name: string;
  protected constructor(theName: string) { this.name = theName; }
}
// Employee 能夠繼承 Person
class Employee 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 Employee("Howard", "Sales");
let john = new Person("John"); // 錯(cuò)誤:因?yàn)?Person' 的構(gòu)造函數(shù)是被保護(hù)的.
// private
class Person {
  private name: string;
  constructor(n: string) {
    this.name = n;
  }
  run(): void {
    console.log(this.name);
  }
}

class Student extends Person {
  constructor(name: string) {
    super(name);
  }
  work(): void {
    console.log(this.name);
  }
}
let s = new Student("李四");
console.log(s.name); // 報(bào)錯(cuò)
s.work(); // 報(bào)錯(cuò)
s.run(); // 李四,因?yàn)閞un方法是Person內(nèi)部的,可以使用私有屬性

參數(shù)屬性

參數(shù)屬性通過給構(gòu)造函數(shù)參數(shù)前面添加一個(gè)訪問限定符來聲明。 使用 private限定一個(gè)參數(shù)屬性會(huì)聲明并初始化一個(gè)私有成員,對于 publicprotected來說也是一樣

總的來說,這種寫法是上面先聲明又賦值屬性的簡便寫法,可以直接通過這種寫法改寫上方先先在前面聲明屬性的寫法,構(gòu)造函數(shù)中也可以什么都不寫

  • 聲明了一個(gè)構(gòu)造函數(shù)參數(shù)及其類型

  • 聲明了一個(gè)同名的公共屬性

  • 當(dāng)我們 new出該類的一個(gè)實(shí)例時(shí),把該屬性初始化為相應(yīng)的參數(shù)值

    class Octopus {
      readonly numberOfLegs: number = 8;
      constructor(readonly name: string) { // 通過這種寫法改變上面對應(yīng)readonly的例子
      }
    }
    

4. 寄存器

TypeScript中也可以對一個(gè)屬性時(shí)用getset方法對一個(gè)屬性內(nèi)部的獲取和賦值進(jìn)行攔截

let passcode = "secret passcode";

class Employee {
  private _fullName: string;
  get fullName(): string { // 對fullName屬性進(jìn)行攔截
    return this._fullName;
  }
  set fullName(newName: string) {
    if (passcode && passcode == "secret passcode") {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
  alert(employee.fullName);
}

只帶有 get不帶有 set的存取器自動(dòng)被推斷為readonly類型的屬性


5. 靜態(tài)方法和屬性

class Person {
  public name: string;
  constructor(n: string) {
    this.name = n;
  }
  run(): void {
    console.log(this.name);
  }
}

class Student extends Person {
  static name1: string; // 設(shè)置靜態(tài)屬性
  constructor(name: string) {
    super(name);
    Student.name1 = this.name; // 賦值
  }
  static work(): void { // 靜態(tài)方法
    console.log(Student.name1);
  }
  work(): void {
    console.log(Student.name1);
  }
}
let s = new Student("李四");
console.log(Student.name1); // 李四
Student.work();
s.work(); // 李四

6. 抽象類

TypeScript中的抽象類是提供其他類繼承的基類,不能直接被實(shí)例化,只能被其他類所繼承

abstract關(guān)鍵字定義抽象類和抽象類中的抽象方法或?qū)傩?,抽象類中的抽象方法不包含具體實(shí)現(xiàn),但是必須要在派生類,也就是繼承的類中實(shí)現(xiàn)抽象方法,抽象屬性不需要賦值,并且繼承的類不能夠擴(kuò)展自己的方法和屬性

總的來說,抽象類和抽象方法只是用來定義一個(gè)標(biāo)準(zhǔn),而在其子類在必須要實(shí)現(xiàn)這個(gè)標(biāo)準(zhǔn),并且不能擴(kuò)展抽象類中沒有的標(biāo)準(zhǔn)。否則會(huì)報(bào)錯(cuò)

abstract聲明的抽象方法只能放在抽象類中。否則會(huì)報(bào)錯(cuò)

abstract class Department {
  abstract age: number;
  constructor(public name: string) { // 參數(shù)屬性的一個(gè)應(yīng)用
  }

  printName(): void {
    console.log('Department name: ' + this.name);
  }

  abstract printMeeting(): void; // 必須在派生類中實(shí)現(xiàn)
}

class AccountingDepartment extends Department {
  public age: number = 18;
  constructor() {
    super('Accounting and Auditing'); // 在派生類的構(gòu)造函數(shù)中必須調(diào)用 super()
  }
  printMeeting(): void {
    console.log('The Accounting Department meets each Monday at 10am.');
  }
  generateReports(): void {
    console.log('Generating accounting reports...');
  }
}

let department: Department; // 允許創(chuàng)建一個(gè)對抽象類型的引用
department = new Department(); // 錯(cuò)誤: 不能創(chuàng)建一個(gè)抽象類的實(shí)例
department = new AccountingDepartment(); // 允許對一個(gè)抽象子類進(jìn)行實(shí)例化和賦值
console.log(department.age); // 18
department.printName();
department.printMeeting();
department.generateReports(); // 錯(cuò)誤: 方法在聲明的抽象類中不存在
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容