iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0

getter應用:

getter除了用來作唯讀的功能,另外有種應用是當需要對屬性data作一些處理後再輸出時,使用getter可以把處理過後的結果存在另一個"屬性"裡,像是下面的例子:

  • 把firstName和lastName組合起來變成fullName
  • 把birthYear拿來作計算後,存在age
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應用:資料驗證

下面的例子是把資料驗證的條件寫在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應用:歷程記錄

下面的例子使用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,它的回答如果又有我不懂的點,我就再抓那個點再繼續問,踩著不放到最後,雖然它也是會出錯,但其實可以是個蠻好的工具(或好朋友)

Reference

Property getters and setters


上一篇
getter & setter到底要幹嘛
下一篇
如何在js實現傳統oop的class繼承
系列文
超低腦容量學習法遇到javascript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言