TS學習筆記(三):類

半掩時光發表於2019-04-20

傳統的 JavaScript 程式使用函式和基於原型的繼承來建立可重用的元件,從 ES6 開始,JavaScript 程式能夠使用基於類的物件導向的方式。使用 TypeScript,你可以使用 ES6 中規定的新特性,編譯後的 JavaScript 可以在所有主流瀏覽器和平臺上執行。

基本用法

class Person {
  public love: string;
  constructor(love: string) {
    this.love = love;
  }
  public sayLove() {
    console.log(`my love is ${this.love}`)
  }
}

複製程式碼

繼承

在構造器裡訪問 this 的屬性之前,一定要呼叫 super() ,這個是 TypeScript 強制執行的一條重要規則。

class Person {
  public love: string;
  constructor(love: string) {
    this.love = love;
  }
  public sayLove() {
    console.log(`my love is ${this.love}`)
  }
}

class SuperPerson extends Person {
  public name: string;
  constructor(love: string, name: string) {
    super(love);
    this.name = name;
  }
  public sayName(){
    console.log(`my name is ${this.name}`)
  }
}

let me = new SuperPerson('HTML', 'funlee');
me.sayLove()
me.sayName()
複製程式碼

訪問控制

public、private、protected

預設是 public, 不再贅述,參考前面例子。

當成員標記為 private 時,它就不能在宣告它的類的外部訪問,用 protected 修飾的屬性依然如此。

class Person {
  private love: string; // or  prot
  constructor(love: string) {
    this.love = love;
  }
  public sayLove() {
    console.log(`my love is ${this.love}`)
  }
}

let me = new Person('TS');
me.love = 'JS'; // error

複製程式碼

private 和 protected 有一點不同, protected 成員在派生類中仍然可以訪問。例如:

class Person {
  protected name: string; 
  constructor(name: string) {
    this.name = name;
  }
}
class Man extends Person {
  private love: string;
  constructor(name: string, love: string) {
    super(name);
    this.love = love;
  }
  public say() {
    // 如果Person 中用 private 修飾 name 則不能訪問到 name 屬性
    console.log(`my name is ${this.name}, and my love is ${this.love}`);
  }
}
let me = new Man('funlee', 'TS');

複製程式碼

注意:TypeScript 使用的是結構性型別系統,所以當比較兩種不同的型別時,如果所有的成員的型別都是相容的,那麼這兩個型別就是相容的。如:

class A {
  prop1: string
}
class B {
  prop1: string
  prop2: string
}
let instance:A = new B() // 允許這麼做,因為A的所有成員型別,B中都有

複製程式碼

但是如果被比較的類裡面含有 private 和 protected 型別成員的時候,情況就不同了,這時候需要另一個類裡也含有相應的 private 或 protected 成員,型別才能是相容的,所以有:

class A {
  private prop1: string
}
class B {
  private prop2: string
}
let p1:A = new B() // 報錯
class C extends A {

}
let p2:A = new C() // 允許這麼做

複製程式碼

readonly

可以使用 readonly 關鍵字將屬性設定為只讀的,只讀屬性必須在宣告時或建構函式裡被初始化。

class Person {
  readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
}
let me = new Person('funlee');
me.name = 'new name'; // error

複製程式碼

引數屬性

引數屬性允許同時建立初始化成員,可以把宣告和賦值合併至一處,如:

class Person {
  constructor(public name: string, protected love: string, readonly age: number, private weight: string) {
    this.name = name;
    this.love = love;
    this.age = age;
  }
  public sayWeight() {
    console.log(`my weight is ${this.weight}`)
  }
}
let me = new Person('funlee', 'TS', 18, '55kg');
me.sayWeight()

複製程式碼

存取器

TypeScript 支援 getter 和 setter,但是有一點限制:編譯器輸出必須設為 ES5 或者更高,不支援降級到 ES3,另外,當一個存取器只帶有 get 卻不帶有 set 時,它會被自動推斷為 readonly。

class Person {
  public _love: string;
  constructor(love: string) {
    this._love = love;
  }
  get love(): string{
    return this._love;
  }
  set love(newLove: string) {
    this._love = `error!! my love can't be chenged`;
  }
}
let me = new Person('TS');
console.log(me.love); // TS
me.love = 'HTML';
console.log(me.love); // error!! my love can't be chenged

複製程式碼

靜態屬性

可以使用static來定義類裡的靜態屬性,靜態屬性屬於類自身,而不屬於例項,訪問的時候要用類名訪問,而不能用例項物件訪問,如:

class Person {
  static love: string = 'TS';
}
let me = new Person();
console.log(Person.love); // TS
console.log(me.love); // error

複製程式碼

抽象類

抽象類只能作為其他派生類的基類使用,抽象類不能被例項化,它具有如下特點:

  • 抽象類可以包含成員的實現細節,且抽象類必須用 abstract 宣告
  • 抽象類裡不含方法體的方法稱為抽象方法,使用 abstract 宣告,抽象方法必須被子類實現(抽象方法必須使用 abstract 關鍵字宣告,且可以包含訪問修飾符)
abstract class Person {
  public love: string;
  constructor(love: string) {
    this.love = love;
  }
  abstract sayLove(): string; // 必須在派生類中實現
}
class Man extends Person{
  constructor(love: string){
    super(love)
  }
  sayLove() {
    return `my love is ${this.love}`;
  }
}
let me = new Man('TS');
console.log(me.sayLove()); // my love is TS

複製程式碼

把類當做介面使用

類定義會建立兩個東西:類的例項型別和一個建構函式,因為類可以建立出型別,所以能夠在允許使用介面的地方使用類。

class Person {
  name: string;
  age: number;
}
interface Man extends Person {
  love: string;
}
let me: Man = {
  name: 'funlee',
  age: 18,
  love: 'TS'
}

複製程式碼

相關文章