iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 23
2

在 TS 中類別有些屬性,我們希望只在類別內部操作,這時候會使用 private 修飾符,如此,該屬性就無法在外部存取,提高資料的安全性。但如果這時候,我們想要操作這些屬性怎麼辦呢?

第一種方式是透過 public 的建構函式,在實例化類別時傳入參數進行賦值; 第二種就是下面會提到的存取器方法 getter 和 setter。

存取器(Accessors)- getter 和 setter

TS 中可以透過 getter 和 setter 來「存」或「取」物件屬性值,幫助更靈活的控制物件屬性的調用。

下面範例程式碼,Employee 類別屬性屬於 public,因此,任何地方都可以進行存取,非常方便,但也很可能會造成安全性的問題。

class Employee {
    fullName: string;
}

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

這時候,試著把 fullName 加上 private 修飾符

class Employee {
    private fullName: string = 'Kira';
}

let employee = new Employee();
//直接賦值 fullName
employee.fullName = "Bob Smith"; //Error: Property 'fullName' is private and only accessible within class 'Employee'.

//取得fullName值
if (employee.fullName) {
    console.log(employee.fullName); ////Error: Property 'fullName' is private and only accessible within class 'Employee'.
}

這時候,完全無法讀取 Employee 類別的 fullName 屬性,那如果想要彈性一點,例如:存值前進行檢查,但在外面仍然可以讀值怎麼辦?這時候就可以用存取器 getter 和 setter 方法。

我們可以改成下面較安全的版本,必須先檢查用戶密碼是否正確,然後才允許修改員工資訊。原本可以直接改值的 fullName ,換成在改動前需要檢查密碼的 set 方法,也加了一個 getter 方法,因此,仍然可以在類別外面取值。換句話說,原本可以直接存取的屬性或方法,改成「存」和「取」分開的取值方法 getter 和存值方法 setter ,來提高操作的安全性。

let passcode = "secret passcode";

class Employee {
    private _fullName: string;
    //取值方法 Getter Method
    get fullName(): string {
        return this._fullName;
    }
    //存值方法Setter Method
    set fullName(newName: string) {
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("錯誤: 沒有授權");
        }
    }
}

//實例化類別 Employee
let employee = new Employee();

employee.fullName = "Una Lin";
if (employee.fullName) {
    alert(employee.fullName); //Una Lin
}

取值方法就是使用 get 關鍵字搭配方法名稱,而存值方法就是 set 關鍵字搭配方法名稱;這時候,如果修改一下密碼:

let passcode ="wrong passcode"

在 set 存值方法中不符合原先預設的密碼,就會印出錯誤: 沒有授權 來。

倘若我們存值時,存入不合型別的資料也會報錯,例如:

employee.fullName = 123; //Error : Type '123' is not assignable to type 'string'.

倘若類別中只有取值方法呢?

class Employee {
    private _fullName: string;
    //取值方法 Getter Method
    get fullName(): string {
        return this._fullName;
    }
}

let employee = new Employee();

employee.fullName = "Una Lin"; //Error: Cannot assign to 'fullName' because it is a read-only property.

這時候,類別只有 getter 沒有 setter 方法,會發現 fullName 會被自動推論為唯獨屬性(readonly)。換句話說,如果只寫 getter 方法 但沒有 setter 方法的話,我們就不能更改值。

存取器的限制

取值方法(Getter)因為是模擬呼叫屬性的方式進行物件的取值,因此不能有任何參數,而且一定要有回傳值,否則會報錯。

    get fullName(value: any): string {
        return this._fullName;
    }
    //Error: A 'get' accessor cannot have parameters.
    get fullName(value: any): string {
        console.log('Una');
    }
    //Error: A 'get' accessor must return a value.

而存值方法(Setter)則是模擬指派任何值到屬性的方式進行物件的存值,只能有一個參數


 set fullName(newName: string, oldName:string) {
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("錯誤: 沒有授權");
        }
    }
    //Error : A 'set' accessor must have exactly one parameter.

要注意的是,要使用存取方法,編譯器輸出的 JS 一定要 ES5以上,不支援 ES3 版本以下。

小結

今天介紹了類別的存取器(Accessor)功能,來個重點整理吧!

來個重點整理:存取器 - Getter & Setter

  1. 存取器主要用在對 private 私有屬性進行間接地操作,如此,可以提高屬性的安全性,同時又保證屬性的封閉性。
  2. getter 主要模擬呼叫物件的屬性時的行為,setter模擬指賦值到物件屬性的行為,兩者皆是使用函式做到屬性的讀取
  3. 若僅有實踐某物件屬性的 getter,沒有setter,則該物件屬性自動推斷為唯獨狀態(readonly)
  4. getter 不能有參數,且一定要有回傳值; setter 只能有一個參數

上一篇
【Day 22】TypeScript 類別繼承(Class Inheritance) v.s. 實踐(Implements)
下一篇
【Day 24】在 React 專案中使用 TypeScript - 建置開發環境
系列文
Typescript 初心者手札30

尚未有邦友留言

立即登入留言