getter除了用來作唯讀的功能,另外有種應用是當需要對屬性data作一些處理後再輸出時,使用getter可以把處理過後的結果存在另一個"屬性"裡,像是下面的例子:
class PerosnCl {
constructor(firstName, lastName, bityhYear, password) {
this.firstName = firstName;
this.lastName = lastName;
this.bityhYear = bityhYear;
this.password = password;
this.pwLog = [];
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
get age() {
return 2023 - this.bityhYear;
}
}
const john = new PerosnCl("John", "Cooper", 2000, "1234");
console.log(john.fullName);
console.log(john.age);
下面的例子是把資料驗證的條件寫在setter裡,用一個if條件式來做一個類似閘道的東西,如果符合條件,在建立instance就能順利寫入屬性,若不符條件,則跳出一個警告視窗。
像是我們希望密碼的設定至少要有四個字元,所以針對password屬性寫了一個setter,在建立instance時,因為new運算子會自動執行constructor函式的內容,而裡面含有觸發setter的程式碼:this.password = password;
,記得嗎?我們把setter看成一個屬性,所以要執行setter時,我們會用john.password
,這就是為什麼在建立instance時,setter同時也會執行。
class PerosnCl {
constructor(firstName, lastName, bityhYear, password) {
this.firstName = firstName;
this.lastName = lastName;
this.bityhYear = bityhYear;
this.password = password;
}
set password(pw) {
if (pw.length >= 4) {
this._password = pw;
} else {
alert("你的密碼長度必須大於4");
}
}
set resetPassword(reset) {
if (reset.length >= 4) {
this._password = reset;
} else {
alert("你的密碼長度必須大於4");
}
}
get readPassword() {
return this._password;
}
}
const john = new PerosnCl("John", "Cooper", 2000, "123");
另外有一件事需要特別注意,在setter裡面,我們使用了_passwprd
取代了password
,這是因為,如果我們仍然用password作為密碼的屬性名稱,像下面這樣,那麼在setter程式在執行到this.password=pw
時,又會再觸發一次setter,所以會產生無限遞迴的現象(不斷地呼叫自己),使用下底線也是一種約定俗成,代表這個屬性是需要受到保護,不可直接修改的。
下面的例子使用setter來作歷程記錄,先建立一個空的陣列,把屬性變化的歷程都push進這個陣列裡,於是可以得到記錄。
像是我們希望能把設定過的密碼都記錄起來,所以在上面例子中的第一個setter裡多加了this.pwLog.push(pw)
,第二的setter加了this.pwLog(reset)
, 意思是如果有順利新增或變更密碼,同時把密碼寫進陣列裡作記錄。
class PerosnCl {
constructor(firstName, lastName, bityhYear, password) {
this.firstName = firstName;
this.lastName = lastName;
this.bityhYear = bityhYear;
this.pwLog = [];
this.password = password;
}
set password(pw) {
if (pw.length >= 4) {
this._password = pw;
this.pwLog.push(pw);
} else {
alert("你的密碼長度必須大於4");
}
}
set resetPassword(reset) {
if (reset.length >= 4) {
this._password = reset;
this.pwLog.push(reset);
} else {
alert("你的密碼長度必須大於4");
}
}
get readPassword() {
return this._password;
}
}
const john = new PerosnCl("John", "Cooper", 2000, "1234");
console.log(john.pwLog);
john.resetPassword = "1111";
console.log(john.pwLog);
這裡要順便說一下自己遇到的bug,剛開始的時候,constructor中的順序有點不太對,造成有個變數還沒被初始化就被呼叫,就被報錯了。
當我們使用new去建立一個新的instance,construcotr中的程式會自動執行,當執行到紅框的this.password=password,則觸發了setter函式,所以js沒將pwLog初始化就跳到setter那邊,此時對js而言,pwLog其實是undefined,所以要push東西進去就報錯了。
之前之所以會覺得不是很懂getter 和 setter是因為有一些點卡住但沒真的去弄清楚,其實這次看,我是把我卡住的地方丟給chatgpt,它的回答如果又有我不懂的點,我就再抓那個點再繼續問,踩著不放到最後,雖然它也是會出錯,但其實可以是個蠻好的工具(或好朋友)