在 TS 中類別有些屬性,我們希望只在類別內部操作,這時候會使用 private 修飾符,如此,該屬性就無法在外部存取,提高資料的安全性。但如果這時候,我們想要操作這些屬性怎麼辦呢?
第一種方式是透過 public 的建構函式,在實例化類別時傳入參數進行賦值; 第二種就是下面會提到的存取器方法 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
- 存取器主要用在對 private 私有屬性進行間接地操作,如此,可以提高屬性的安全性,同時又保證屬性的封閉性。
- getter 主要模擬呼叫物件的屬性時的行為,setter模擬指賦值到物件屬性的行為,兩者皆是使用函式做到屬性的讀取
- 若僅有實踐某物件屬性的 getter,沒有setter,則該物件屬性自動推斷為唯獨狀態(readonly)
- getter 不能有參數,且一定要有回傳值; setter 只能有一個參數