iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 21
1
自我挑戰組

Typescript 初心者手札系列 第 21

【Day 21】TypeScript 類別 -存取修飾符(Access Modifiers)、抽象( Abstract)

昨天簡單的介紹了類別的基本用法和繼承概念,今天來繼續探討類別中蠻重要的功能-存取修飾符(Access Modifiers)以及abstract關鍵字。

存取修飾符(Access Modifiers)

什麼是存取修飾符(Access Modifiers) 呢?存取修飾符用來限制類別中的屬性或方法在類別內部或外部被呼叫的權限。目前類別存取修飾符共有三種 - public、private 以及 protected,整理如下:

  • public - 屬性或方法是公開的,可以任意任何地方使用(預設值)
  • private - 屬性或方法是私有的,只能在本身類別內部使用
  • protected - 屬性或方法受到保護,只能在本身類別內以及繼承的子類別中使用
是否可存取 public private protected
類別本身 可以 可以 可以
繼承的子類別 可以 不行 可以
類別的物件實例 可以 不行 不行

存取修飾符語法與範例

存取修飾符會標註在類別內部屬性或方法名稱的前面。範例程式碼如下:

class Foo {
    constructor(theX: number, theY:number, theZ: number) {
        this.x = theX;
        this.y = theY;
        this.z = theZ
    }
    public x: number;
    private y: number;
    protected z: number;
}

// 將類別實例化,創造新物件 foo
let foo = new Foo(2,3,4);
foo.x =1; // OK
foo.y =1; // ERROR (private 修飾符):Property 'y' is private and only accessible within class 'Foo'.
foo.z =1; // ERROR (protected 修飾符): Property 'z' is protected and only accessible within class 'Foo' and its subclasses.

// 繼承的子類別 FooChild
class FooChild extends Foo {
    constructor(x:number, y:number, z: number) {
      super(x,y,z);
        this.x =0; // OK
        this.y =0 ; // ERROR(private 修飾符): Property 'y' is private and only accessible within class 'Foo'.
        this.z = 0 // OK
        this.a = 'hello'
    }
    private a : string 
}

在上方的程式碼中,你會發現標註 public 的屬性或方法在類別本身或外部都可以存取,而標註 private 則只在類別本身內部可存取,protected 的存取限制則介於兩者之間,在繼承的子類別中可以存取,實例化物件則無法存取。

抽象(Abstract)

abstract是 TS 1.6版本加入的新關鍵字,可以加在類別名稱類別方法的前面,用來限制類別的實例化,特性摘要如下:

  1. abstract 加在類別名稱前,表示類別僅供其他類別繼承/擴展,但不允許使用 new 關鍵字進行實例化
  2. abstract 加在類別方法前,表示此方法不允許實例化
  3. 倘若類別中有抽象方法,則該類別一定要註記為抽象類別
  4. 類別方法不會同時 abstract 和 static,也不會同時 abstract 和private
  5. 抽象類別方法若要加上存取修飾符,則存取修飾符必須在 abstract 關鍵字前面
  6. 抽象類別可以繼承/擴展,但繼承的子類別必須實踐抽象方法

完整abstract關鍵字的特性說明請參考此說明

範例程式碼如下:

class A {
    // ...
}

abstract class B {
    foo(): number { return bar(); }
    abstract bar() : number;
}

new B; // Error : B為抽象類別,無法創建實例

class C extends B { } // Error : 非抽象類別C繼承抽象類別B,必須實作抽象方法bar()
abstract class D extends B { } // OK
class E extends B {           // OK:有實作抽象方法
    bar() { return 1; }

靜態屬性與方法(Static Properties an methods)

類別內的屬性和方法其實分為兩種:實例 ( Instance )和靜態 ( Static )。Static 在 ES6 就出現了,但在 ES6 的 Class 中只有靜態屬性,沒有靜態方法,而在 TS 中,靜態屬性和方法都有。

預設狀況下,所有在類別中定義的方法和屬性都會被實例繼承,但如果加上 static 關鍵字,轉換成靜態屬性和方法後,則表示該方法或屬性不會被實例繼承,僅存在類別內部,倘若要使用會直接透過類別來調用。

class Something {
    static instances = 0;
    static foo():number {
     return 42;
  }
}
//繼承的子類別SomethingMore
class SomethingMore extends Something { }
console.log(SomethingMore.foo()); // 42

//實例化物件s1
const s1 = new Something();
console.log(s1.instances) //Error: Property 'instances' is a static member of type 'Something'
console.log(Something.instances); // 0

上面的程式碼中,由於 instances 屬性為靜態屬性,因此,實例化的物件 s1 並沒有 instances 這個屬性,若要調用,就必須直接透過類別來調用靜態屬性 instances。另外,繼承的子類別 SomethingMore 中可調用父類別的靜態方法foo()。

小結

今天探討了類別內屬性和方法的細節,包括靜態屬性和方法、存取修飾符以及抽象化,明天會繼續探討類別的實踐(implements)。


上一篇
【Day 20】TypeScript 資料型別 - 類別(Class)
下一篇
【Day 22】TypeScript 類別繼承(Class Inheritance) v.s. 實踐(Implements)
系列文
Typescript 初心者手札30

尚未有邦友留言

立即登入留言